"use client";

import { type CSSProperties, useEffect, useMemo, useState } from "react";
import Map from "@/components/Map";
import { ApiError } from "@/api/http";
import {
    approveSubmission,
    fetchSections,
    fetchSectionSubmissions,
    rejectSubmission,
    Section,
    SectionSubmission,
} from "@/api/sections";
import { HIDDEN_BACKGROUND_LAYER_VISIBILITY } from "@/lib/backgroundLayers";
import { Feature, FeatureCollection, Geometry } from "@/lib/useEditorState";

type SubmissionStatusFilter = "pending" | "all";
type ReviewAction = "approve" | "reject";

type SubmissionRow = {
    section: Section;
    submission: SectionSubmission;
};

type SnapshotSummary = {
    featureCount: number;
    entityCount: number;
    geometryCount: number;
    linkScopeCount: number;
    entityOperations: Record<string, number>;
    geometryOperations: Record<string, number>;
    linkOperations: Record<string, number>;
};

const DEFAULT_REVIEWER_ID = "admin";
const EMPTY_FEATURE_COLLECTION: FeatureCollection = {
    type: "FeatureCollection",
    features: [],
};
const REVIEW_BACKGROUND_LAYER_VISIBILITY = {
    ...HIDDEN_BACKGROUND_LAYER_VISIBILITY,
    "bg-countries-fill": true,
    "bg-country-borders-line": true,
};

const STATUS_LABELS: Record<SectionSubmission["status"], string> = {
    pending: "Chờ duyệt",
    approved: "Đã duyệt",
    rejected: "Từ chối",
    conflicted: "Conflict",
};

export default function SubmittedPage() {
    const [rows, setRows] = useState<SubmissionRow[]>([]);
    const [selectedSubmissionId, setSelectedSubmissionId] = useState<string | null>(null);
    const [statusFilter, setStatusFilter] = useState<SubmissionStatusFilter>("pending");
    const [reviewerId, setReviewerId] = useState(DEFAULT_REVIEWER_ID);
    const [reviewNote, setReviewNote] = useState("");
    const [isLoading, setIsLoading] = useState(true);
    const [reviewingSubmissionId, setReviewingSubmissionId] = useState<string | null>(null);
    const [selectedPreviewFeatureId, setSelectedPreviewFeatureId] = useState<string | number | null>(null);
    const [isJsonPopupOpen, setIsJsonPopupOpen] = useState(false);
    const [statusMessage, setStatusMessage] = useState<string | null>(null);
    const [errorMessage, setErrorMessage] = useState<string | null>(null);

    const loadSubmissions = async () => {
        setIsLoading(true);
        setErrorMessage(null);
        setStatusMessage(null);

        try {
            const sections = await fetchSections();
            const submissionGroups = await Promise.all(
                sections.map(async (section) => {
                    const submissions = await fetchSectionSubmissions(section.id, {
                        includeSnapshot: true,
                    });
                    return submissions.map<SubmissionRow>((submission) => ({
                        section,
                        submission,
                    }));
                })
            );
            const nextRows = submissionGroups
                .flat()
                .sort((a, b) =>
                    Date.parse(b.submission.submitted_at) - Date.parse(a.submission.submitted_at)
                );

            setRows(nextRows);
            setSelectedSubmissionId((current) => {
                if (current && nextRows.some((row) => row.submission.id === current)) {
                    return current;
                }
                return nextRows.find((row) => row.submission.status === "pending")?.submission.id
                    || nextRows[0]?.submission.id
                    || null;
            });
        } catch (err) {
            setErrorMessage(getErrorMessage(err, "Không tải được danh sách section đã submit."));
        } finally {
            setIsLoading(false);
        }
    };

    useEffect(() => {
        loadSubmissions();
    }, []);

    const visibleRows = useMemo(() => {
        if (statusFilter === "all") return rows;
        return rows.filter((row) => row.submission.status === "pending");
    }, [rows, statusFilter]);

    const selectedRow = useMemo(() => {
        if (!selectedSubmissionId) return visibleRows[0] || null;
        return (
            visibleRows.find((row) => row.submission.id === selectedSubmissionId) ||
            rows.find((row) => row.submission.id === selectedSubmissionId) ||
            visibleRows[0] ||
            null
        );
    }, [rows, selectedSubmissionId, visibleRows]);

    const pendingCount = rows.filter((row) => row.submission.status === "pending").length;
    const reviewedCount = rows.length - pendingCount;
    const selectedSummary = selectedRow
        ? summarizeSnapshot(selectedRow.submission.snapshot)
        : null;
    const selectedFeatureCollection = selectedRow
        ? extractSnapshotFeatureCollection(selectedRow.submission.snapshot)
        : EMPTY_FEATURE_COLLECTION;
    const selectedPreviewFeature = selectedFeatureCollection.features.find((feature) =>
        String(feature.properties.id) === String(selectedPreviewFeatureId)
    ) || null;

    useEffect(() => {
        setSelectedPreviewFeatureId(null);
        setIsJsonPopupOpen(false);
    }, [selectedRow?.submission.id]);

    const handleReview = async (action: ReviewAction) => {
        if (!selectedRow) return;
        const actor = reviewerId.trim();
        if (!actor) {
            setErrorMessage("Reviewer là bắt buộc.");
            return;
        }
        if (selectedRow.submission.status !== "pending") {
            setErrorMessage("Submission này không còn ở trạng thái chờ duyệt.");
            return;
        }

        const label = action === "approve" ? "duyệt" : "từ chối";
        const confirmed = window.confirm(`Xác nhận ${label} section "${selectedRow.section.title}"?`);
        if (!confirmed) return;

        setReviewingSubmissionId(selectedRow.submission.id);
        setErrorMessage(null);
        setStatusMessage(null);

        try {
            const input = {
                reviewed_by: actor,
                review_note: reviewNote.trim() || null,
            };
            const updatedSubmission = action === "approve"
                ? await approveSubmission(selectedRow.submission.id, input)
                : await rejectSubmission(selectedRow.submission.id, input);

            setRows((currentRows) =>
                currentRows.map((row) =>
                    row.submission.id === updatedSubmission.id
                        ? {
                            ...row,
                            section: {
                                ...row.section,
                                state: {
                                    ...row.section.state,
                                    status: updatedSubmission.status === "approved"
                                        ? "approved"
                                        : updatedSubmission.status === "rejected"
                                            ? "rejected"
                                            : row.section.state.status,
                                },
                            },
                            submission: updatedSubmission,
                        }
                        : row
                )
            );
            setReviewNote("");
            setStatusMessage(
                action === "approve"
                    ? "Đã duyệt submission và apply vào published data."
                    : "Đã từ chối submission."
            );
        } catch (err) {
            setErrorMessage(getErrorMessage(err, `Không thể ${label} submission.`));
        } finally {
            setReviewingSubmissionId(null);
        }
    };

    const isReviewingSelected = reviewingSubmissionId === selectedRow?.submission.id;
    const canReviewSelected = Boolean(
        selectedRow &&
        selectedRow.submission.status === "pending" &&
        !isReviewingSelected
    );

    return (
        <main style={styles.page}>
            <section style={styles.header}>
                <div>
                    <p style={styles.kicker}>Review sections</p>
                    <h1 style={styles.title}>Submitted sections</h1>
                    <p style={styles.subtitle}>
                        Xem các section đã submit, kiểm tra snapshot và duyệt dữ liệu vào published map.
                    </p>
                </div>
                <div style={styles.headerActions}>
                    <a href="/editor" style={styles.secondaryLink}>Mở editor</a>
                    <button
                        type="button"
                        onClick={loadSubmissions}
                        disabled={isLoading}
                        style={styles.primaryButton}
                    >
                        {isLoading ? "Đang tải..." : "Refresh"}
                    </button>
                </div>
            </section>

            <section style={styles.statsGrid}>
                <Metric label="Tổng submission" value={rows.length} />
                <Metric label="Chờ duyệt" value={pendingCount} />
                <Metric label="Đã xử lý" value={reviewedCount} />
            </section>

            {statusMessage ? <div style={styles.successBanner}>{statusMessage}</div> : null}
            {errorMessage ? <div style={styles.errorBanner}>{errorMessage}</div> : null}

            <section style={styles.toolbar}>
                <label style={styles.fieldLabel}>
                    Reviewer
                    <input
                        value={reviewerId}
                        onChange={(event) => setReviewerId(event.target.value)}
                        style={styles.input}
                        placeholder="reviewer id"
                    />
                </label>
                <label style={styles.fieldLabelWide}>
                    Ghi chú review
                    <input
                        value={reviewNote}
                        onChange={(event) => setReviewNote(event.target.value)}
                        style={styles.input}
                        placeholder="Ghi chú optional"
                    />
                </label>
                <label style={styles.fieldLabel}>
                    Bộ lọc
                    <select
                        value={statusFilter}
                        onChange={(event) =>
                            setStatusFilter(event.target.value as SubmissionStatusFilter)
                        }
                        style={styles.input}
                    >
                        <option value="pending">Chờ duyệt</option>
                        <option value="all">Tất cả</option>
                    </select>
                </label>
            </section>

            <section style={styles.contentGrid}>
                <div style={styles.listPanel}>
                    <div style={styles.panelHeader}>
                        <h2 style={styles.panelTitle}>Sections</h2>
                        <span style={styles.mutedText}>{visibleRows.length} item</span>
                    </div>

                    {isLoading ? (
                        <div style={styles.emptyState}>Đang tải submissions...</div>
                    ) : visibleRows.length === 0 ? (
                        <div style={styles.emptyState}>
                            Không có submission nào trong bộ lọc hiện tại.
                        </div>
                    ) : (
                        <div style={styles.submissionList}>
                            {visibleRows.map((row) => {
                                const selected = selectedRow?.submission.id === row.submission.id;
                                return (
                                    <button
                                        key={row.submission.id}
                                        type="button"
                                        onClick={() => setSelectedSubmissionId(row.submission.id)}
                                        style={{
                                            ...styles.submissionItem,
                                            ...(selected ? styles.submissionItemSelected : null),
                                        }}
                                    >
                                        <span style={styles.itemTopLine}>
                                            <strong style={styles.itemTitle}>{row.section.title}</strong>
                                            <StatusBadge status={row.submission.status} />
                                        </span>
                                        <span style={styles.itemMeta}>
                                            Submit bởi {row.submission.submitted_by || "unknown"}
                                        </span>
                                        <span style={styles.itemMeta}>
                                            {formatDateTime(row.submission.submitted_at)}
                                        </span>
                                    </button>
                                );
                            })}
                        </div>
                    )}
                </div>

                <div style={styles.detailPanel}>
                    {!selectedRow ? (
                        <div style={styles.emptyState}>Chọn một section để xem chi tiết.</div>
                    ) : (
                        <>
                            <div style={styles.detailHeader}>
                                <div>
                                    <h2 style={styles.detailTitle}>{selectedRow.section.title}</h2>
                                    <p style={styles.mutedText}>
                                        Section status: {selectedRow.section.state.status} · Version {selectedRow.section.state.version}
                                    </p>
                                </div>
                                <StatusBadge status={selectedRow.submission.status} />
                            </div>

                            <div style={styles.metaGrid}>
                                <Info label="Submission ID" value={selectedRow.submission.id} />
                                <Info label="Commit ID" value={selectedRow.submission.commit_id} />
                                <Info label="Submitted by" value={selectedRow.submission.submitted_by} />
                                <Info label="Submitted at" value={formatDateTime(selectedRow.submission.submitted_at)} />
                                <Info label="Reviewed by" value={selectedRow.submission.reviewed_by || "Chưa có"} />
                                <Info label="Reviewed at" value={formatDateTime(selectedRow.submission.reviewed_at)} />
                            </div>

                            <div style={styles.dataActions}>
                                <button
                                    type="button"
                                    onClick={() => setIsJsonPopupOpen(true)}
                                    style={styles.secondaryButton}
                                >
                                    View commit JSON
                                </button>
                            </div>

                            {selectedRow.submission.review_note ? (
                                <div style={styles.noteBox}>
                                    <strong>Review note</strong>
                                    <p style={styles.noteText}>{selectedRow.submission.review_note}</p>
                                </div>
                            ) : null}

                            {selectedSummary ? (
                                <>
                                    <h3 style={styles.sectionHeading}>Map preview</h3>
                                    {selectedFeatureCollection.features.length > 0 ? (
                                        <div style={styles.previewGrid}>
                                            <div style={styles.mapPreview}>
                                                <Map
                                                    key={selectedRow.submission.id}
                                                    mode="select"
                                                    draft={selectedFeatureCollection}
                                                    backgroundVisibility={REVIEW_BACKGROUND_LAYER_VISIBILITY}
                                                    selectedFeatureId={selectedPreviewFeatureId}
                                                    onSelectFeatureId={setSelectedPreviewFeatureId}
                                                    allowGeometryEditing={false}
                                                    respectBindingFilter={false}
                                                    height="420px"
                                                    fitToDraftBounds
                                                    fitBoundsKey={selectedRow.submission.id}
                                                />
                                            </div>
                                            <div style={styles.featurePanel}>
                                                <strong>Selected geometry</strong>
                                                {selectedPreviewFeature ? (
                                                    <div style={styles.featureDetails}>
                                                        <Info
                                                            label="Geometry ID"
                                                            value={String(selectedPreviewFeature.properties.id)}
                                                        />
                                                        <Info
                                                            label="Geometry type"
                                                            value={selectedPreviewFeature.geometry.type}
                                                        />
                                                        <Info
                                                            label="Semantic type"
                                                            value={selectedPreviewFeature.properties.type || "Chưa có"}
                                                        />
                                                        <Info
                                                            label="Entity"
                                                            value={formatFeatureEntities(selectedPreviewFeature)}
                                                        />
                                                        <Info
                                                            label="Time"
                                                            value={formatFeatureTimeRange(selectedPreviewFeature)}
                                                        />
                                                        <Info
                                                            label="Binding"
                                                            value={formatFeatureBinding(selectedPreviewFeature)}
                                                        />
                                                    </div>
                                                ) : (
                                                    <p style={styles.mutedText}>
                                                        Chọn một geometry trên preview để xem metadata.
                                                    </p>
                                                )}
                                            </div>
                                        </div>
                                    ) : (
                                        <div style={styles.emptyState}>
                                            Submission này không có geometry renderable trong phần cần duyệt.
                                            Nếu đây là thay đổi delete-only, hãy xem phần operation summary bên dưới.
                                        </div>
                                    )}

                                    <h3 style={styles.sectionHeading}>Snapshot</h3>
                                    <div style={styles.summaryGrid}>
                                        <Metric label="Preview features" value={selectedSummary.featureCount} />
                                        <Metric label="Entities in review" value={selectedSummary.entityCount} />
                                        <Metric label="Geometries in review" value={selectedSummary.geometryCount} />
                                        <Metric label="Link scopes" value={selectedSummary.linkScopeCount} />
                                    </div>
                                    <div style={styles.operationGrid}>
                                        <OperationBlock
                                            title="Entity operations"
                                            operations={selectedSummary.entityOperations}
                                        />
                                        <OperationBlock
                                            title="Geometry operations"
                                            operations={selectedSummary.geometryOperations}
                                        />
                                        <OperationBlock
                                            title="Link operations"
                                            operations={selectedSummary.linkOperations}
                                        />
                                    </div>
                                </>
                            ) : (
                                <div style={styles.emptyState}>Submission này không có snapshot để hiển thị.</div>
                            )}

                            <div style={styles.reviewActions}>
                                <button
                                    type="button"
                                    onClick={() => handleReview("reject")}
                                    disabled={!canReviewSelected}
                                    style={styles.dangerButton}
                                >
                                    {isReviewingSelected ? "Đang xử lý..." : "Từ chối"}
                                </button>
                                <button
                                    type="button"
                                    onClick={() => handleReview("approve")}
                                    disabled={!canReviewSelected}
                                    style={styles.approveButton}
                                >
                                    {isReviewingSelected ? "Đang xử lý..." : "Duyệt"}
                                </button>
                            </div>

                            <JsonDataPopup
                                open={isJsonPopupOpen}
                                title={`Commit ${selectedRow.submission.commit_id}`}
                                data={selectedRow.submission.snapshot ?? null}
                                onClose={() => setIsJsonPopupOpen(false)}
                            />
                        </>
                    )}
                </div>
            </section>
        </main>
    );
}

function Metric({ label, value }: { label: string; value: number }) {
    return (
        <div style={styles.metric}>
            <span style={styles.metricValue}>{value}</span>
            <span style={styles.metricLabel}>{label}</span>
        </div>
    );
}

function Info({ label, value }: { label: string; value: string }) {
    return (
        <div style={styles.infoCell}>
            <span style={styles.infoLabel}>{label}</span>
            <span style={styles.infoValue}>{value}</span>
        </div>
    );
}

function JsonDataPopup({
                           open,
                           title,
                           data,
                           onClose,
                       }: {
    open: boolean;
    title: string;
    data: unknown;
    onClose: () => void;
}) {
    useEffect(() => {
        if (!open) return;

        const handleKeyDown = (event: KeyboardEvent) => {
            if (event.key === "Escape") {
                onClose();
            }
        };

        window.addEventListener("keydown", handleKeyDown);
        return () => window.removeEventListener("keydown", handleKeyDown);
    }, [open, onClose]);

    if (!open) return null;

    return (
        <div role="presentation" onClick={onClose} style={styles.jsonOverlay}>
            <section
                role="dialog"
                aria-modal="true"
                aria-label="Commit JSON data"
                onClick={(event) => event.stopPropagation()}
                style={styles.jsonDialog}
            >
                <div style={styles.jsonDialogHeader}>
                    <div>
                        <h3 style={styles.jsonDialogTitle}>{title}</h3>
                        <p style={styles.jsonDialogSubtitle}>Raw data của submission đang duyệt.</p>
                    </div>
                    <button type="button" onClick={onClose} style={styles.jsonCloseButton}>
                        Close
                    </button>
                </div>
                <pre style={styles.jsonPre}>{JSON.stringify(data, null, 2)}</pre>
            </section>
        </div>
    );
}

function StatusBadge({ status }: { status: SectionSubmission["status"] }) {
    return (
        <span
            style={{
                ...styles.statusBadge,
                ...getStatusStyle(status),
            }}
        >
            {STATUS_LABELS[status] || status}
        </span>
    );
}

function OperationBlock({
    title,
    operations,
}: {
    title: string;
    operations: Record<string, number>;
}) {
    const entries = Object.entries(operations);
    return (
        <div style={styles.operationBlock}>
            <strong>{title}</strong>
            {entries.length === 0 ? (
                <p style={styles.mutedText}>Không có operation.</p>
            ) : (
                <div style={styles.operationRows}>
                    {entries.map(([operation, count]) => (
                        <span key={operation} style={styles.operationPill}>
                            {operation}: {count}
                        </span>
                    ))}
                </div>
            )}
        </div>
    );
}

function extractSnapshotFeatureCollection(rawSnapshot: unknown): FeatureCollection {
    if (!rawSnapshot || typeof rawSnapshot !== "object" || Array.isArray(rawSnapshot)) {
        return EMPTY_FEATURE_COLLECTION;
    }

    const snapshot = rawSnapshot as Record<string, unknown>;
    const geometries = Array.isArray(snapshot.geometries) ? snapshot.geometries : [];
    const reviewGeometryIds = getReviewGeometryIds(snapshot);
    const renderableGeometryIds = new Set<string>();
    for (const item of geometries) {
        if (!item || typeof item !== "object" || Array.isArray(item)) continue;
        const source = item as Record<string, unknown>;
        const id = normalizeSnapshotId(source.id);
        if (!id || !reviewGeometryIds.has(id)) continue;
        if (normalizeOperationName(source.operation) === "delete") continue;
        renderableGeometryIds.add(id);
    }

    const editorCollection = snapshot.editor_feature_collection;
    if (isFeatureCollection(editorCollection)) {
        return {
            type: "FeatureCollection",
            features: editorCollection.features
                .filter((feature) => renderableGeometryIds.has(String(feature.properties.id)))
                .map(cloneFeature),
        };
    }

    const features = geometries
        .map((item): Feature | null => {
            if (!item || typeof item !== "object" || Array.isArray(item)) return null;
            const source = item as Record<string, unknown>;

            const id = normalizeSnapshotId(source.id);
            if (!id || !renderableGeometryIds.has(id)) return null;
            const geometry = source.draw_geometry || source.geometry;
            if ((typeof id !== "string" && typeof id !== "number") || !isGeometry(geometry)) {
                return null;
            }

            return {
                type: "Feature",
                properties: {
                    id,
                    type: typeof source.type === "string" ? source.type : null,
                    geometry_preset: null,
                    entity_id: null,
                    entity_ids: [],
                    entity_name: null,
                    entity_type_id: null,
                    binding: normalizeStringArray(source.binding),
                    time_start: normalizeOptionalNumber(source.time_start),
                    time_end: normalizeOptionalNumber(source.time_end),
                },
                geometry: cloneGeometry(geometry),
            };
        })
        .filter((feature): feature is Feature => feature !== null);

    return {
        type: "FeatureCollection",
        features,
    };
}

function summarizeSnapshot(rawSnapshot: unknown): SnapshotSummary | null {
    if (!rawSnapshot || typeof rawSnapshot !== "object" || Array.isArray(rawSnapshot)) {
        return null;
    }

    const snapshot = rawSnapshot as Record<string, unknown>;
    const entities = Array.isArray(snapshot.entities) ? snapshot.entities : [];
    const geometries = Array.isArray(snapshot.geometries) ? snapshot.geometries : [];
    const linkScopes = Array.isArray(snapshot.link_scopes) ? snapshot.link_scopes : [];
    const reviewGeometryIds = getReviewGeometryIds(snapshot);
    const reviewEntities = entities.filter((item) =>
        normalizeOperationName(getRecord(item)?.operation) !== "reference"
    );
    const reviewGeometries = geometries.filter((item) => {
        const record = getRecord(item);
        if (!record) return false;
        const id = normalizeSnapshotId(record.id);
        return Boolean(id && reviewGeometryIds.has(id));
    });

    return {
        featureCount: extractSnapshotFeatureCollection(rawSnapshot).features.length,
        entityCount: reviewEntities.length,
        geometryCount: reviewGeometries.length,
        linkScopeCount: linkScopes.length,
        entityOperations: countOperations(reviewEntities),
        geometryOperations: countOperations(reviewGeometries),
        linkOperations: countOperations(linkScopes),
    };
}

function getReviewGeometryIds(snapshot: Record<string, unknown>): Set<string> {
    const ids = new Set<string>();
    const geometries = Array.isArray(snapshot.geometries) ? snapshot.geometries : [];
    const linkScopes = Array.isArray(snapshot.link_scopes) ? snapshot.link_scopes : [];

    for (const item of geometries) {
        const record = getRecord(item);
        if (!record) continue;
        const id = normalizeSnapshotId(record.id);
        if (!id) continue;
        const operation = normalizeOperationName(record.operation);
        if (operation && operation !== "reference") {
            ids.add(id);
        }
    }

    for (const item of linkScopes) {
        const record = getRecord(item);
        if (!record) continue;
        const geometryId = normalizeSnapshotId(record.geometry_id);
        if (geometryId) ids.add(geometryId);
    }

    return ids;
}

function getRecord(value: unknown): Record<string, unknown> | null {
    if (!value || typeof value !== "object" || Array.isArray(value)) return null;
    return value as Record<string, unknown>;
}

function normalizeSnapshotId(value: unknown): string | null {
    if (typeof value !== "string" && typeof value !== "number") return null;
    const normalized = String(value).trim();
    return normalized.length ? normalized : null;
}

function normalizeOperationName(value: unknown): string {
    return typeof value === "string" ? value.trim().toLowerCase() : "";
}

function isFeatureCollection(value: unknown): value is FeatureCollection {
    if (!value || typeof value !== "object" || Array.isArray(value)) return false;
    const source = value as Record<string, unknown>;
    return source.type === "FeatureCollection" &&
        Array.isArray(source.features) &&
        source.features.every(isFeature);
}

function isFeature(value: unknown): value is Feature {
    if (!value || typeof value !== "object" || Array.isArray(value)) return false;
    const source = value as Record<string, unknown>;
    const properties = source.properties;
    if (source.type !== "Feature" || !isGeometry(source.geometry)) return false;
    if (!properties || typeof properties !== "object" || Array.isArray(properties)) return false;
    const id = (properties as Record<string, unknown>).id;
    return typeof id === "string" || typeof id === "number";
}

function isGeometry(value: unknown): value is Geometry {
    if (!value || typeof value !== "object" || Array.isArray(value)) return false;
    const source = value as Record<string, unknown>;
    return typeof source.type === "string" && Array.isArray(source.coordinates);
}

function cloneFeature(feature: Feature): Feature {
    return JSON.parse(JSON.stringify(feature)) as Feature;
}

function cloneGeometry(geometry: Geometry): Geometry {
    return JSON.parse(JSON.stringify(geometry)) as Geometry;
}

function normalizeStringArray(value: unknown): string[] {
    if (!Array.isArray(value)) return [];
    return value
        .map((item) => {
            if (typeof item !== "string" && typeof item !== "number") return "";
            return String(item).trim();
        })
        .filter((item) => item.length > 0);
}

function normalizeOptionalNumber(value: unknown): number | null {
    if (value === null || value === undefined || value === "") return null;
    const parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : null;
}

function formatFeatureEntities(feature: Feature): string {
    const named = normalizeStringArray(feature.properties.entity_names);
    if (named.length > 0) return named.join(", ");
    if (feature.properties.entity_name) return feature.properties.entity_name;
    const ids = normalizeStringArray(feature.properties.entity_ids);
    if (ids.length > 0) return ids.join(", ");
    return feature.properties.entity_id || "Chưa gắn";
}

function formatFeatureTimeRange(feature: Feature): string {
    const start = feature.properties.time_start;
    const end = feature.properties.time_end;
    if (start == null && end == null) return "Không giới hạn";
    if (start != null && end != null) return `${start} - ${end}`;
    if (start != null) return `Từ ${start}`;
    return `Đến ${end}`;
}

function formatFeatureBinding(feature: Feature): string {
    const binding = normalizeStringArray(feature.properties.binding);
    return binding.length > 0 ? binding.join(", ") : "Không có";
}

function countOperations(items: unknown[]): Record<string, number> {
    return items.reduce<Record<string, number>>((acc, item) => {
        const source = item && typeof item === "object" && !Array.isArray(item)
            ? item as Record<string, unknown>
            : {};
        const operation = typeof source.operation === "string" && source.operation.trim()
            ? source.operation.trim()
            : "unknown";
        acc[operation] = (acc[operation] || 0) + 1;
        return acc;
    }, {});
}

function formatDateTime(value: string | null | undefined): string {
    if (!value) return "Chưa có";
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return value;
    return new Intl.DateTimeFormat("vi-VN", {
        dateStyle: "medium",
        timeStyle: "short",
    }).format(date);
}

function getErrorMessage(err: unknown, fallback: string): string {
    if (err instanceof ApiError) {
        const parsed = parseErrorBody(err.body);
        return parsed || err.body || fallback;
    }
    if (err instanceof Error) return err.message;
    return fallback;
}

function parseErrorBody(body: string): string | null {
    try {
        const parsed = JSON.parse(body) as unknown;
        if (parsed && typeof parsed === "object" && "error" in parsed) {
            const error = (parsed as { error?: unknown }).error;
            return typeof error === "string" ? error : null;
        }
    } catch {
        return null;
    }
    return null;
}

function getStatusStyle(status: SectionSubmission["status"]): CSSProperties {
    if (status === "approved") {
        return {
            background: "#d9f5df",
            color: "#17652a",
            borderColor: "#8bd19a",
        };
    }
    if (status === "rejected") {
        return {
            background: "#ffe2dd",
            color: "#8a1f12",
            borderColor: "#ef9a8d",
        };
    }
    if (status === "conflicted") {
        return {
            background: "#fff1c7",
            color: "#755400",
            borderColor: "#dfbf59",
        };
    }
    return {
        background: "#e2f1ff",
        color: "#0c4f85",
        borderColor: "#8bbde4",
    };
}

const styles: Record<string, CSSProperties> = {
    page: {
        minHeight: "100vh",
        padding: "32px",
        background: "#f7f8f3",
        color: "#1f241f",
    },
    header: {
        display: "flex",
        justifyContent: "space-between",
        gap: "20px",
        alignItems: "flex-start",
        flexWrap: "wrap",
        marginBottom: "22px",
    },
    kicker: {
        margin: "0 0 8px",
        color: "#4f6f39",
        fontSize: "13px",
        fontWeight: 700,
        textTransform: "uppercase",
    },
    title: {
        margin: 0,
        fontSize: "36px",
        lineHeight: 1.15,
        letterSpacing: 0,
    },
    subtitle: {
        maxWidth: "680px",
        margin: "10px 0 0",
        color: "#596055",
        lineHeight: 1.5,
    },
    headerActions: {
        display: "flex",
        gap: "10px",
        flexWrap: "wrap",
        justifyContent: "flex-end",
    },
    primaryButton: {
        minHeight: "38px",
        border: "1px solid #284f2f",
        borderRadius: "8px",
        padding: "8px 14px",
        background: "#2f6d3a",
        color: "#ffffff",
        fontWeight: 700,
        cursor: "pointer",
    },
    secondaryLink: {
        minHeight: "38px",
        border: "1px solid #c7cebc",
        borderRadius: "8px",
        padding: "8px 14px",
        background: "#ffffff",
        color: "#2a3326",
        fontWeight: 700,
        textDecoration: "none",
    },
    statsGrid: {
        display: "grid",
        gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
        gap: "12px",
        marginBottom: "16px",
    },
    metric: {
        border: "1px solid #d5dbc8",
        borderRadius: "8px",
        padding: "14px",
        background: "#ffffff",
    },
    metricValue: {
        display: "block",
        fontSize: "28px",
        lineHeight: 1.1,
        fontWeight: 800,
        color: "#254b2b",
    },
    metricLabel: {
        display: "block",
        marginTop: "6px",
        color: "#5a6356",
        fontSize: "13px",
    },
    successBanner: {
        border: "1px solid #9dcc9c",
        borderRadius: "8px",
        padding: "12px 14px",
        marginBottom: "12px",
        background: "#e6f6e5",
        color: "#1d5b25",
    },
    errorBanner: {
        border: "1px solid #ef9a8d",
        borderRadius: "8px",
        padding: "12px 14px",
        marginBottom: "12px",
        background: "#ffe2dd",
        color: "#8a1f12",
    },
    toolbar: {
        display: "grid",
        gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 220px), 1fr))",
        gap: "12px",
        marginBottom: "16px",
        alignItems: "end",
    },
    fieldLabel: {
        display: "grid",
        gap: "6px",
        color: "#424a3f",
        fontSize: "13px",
        fontWeight: 700,
    },
    fieldLabelWide: {
        display: "grid",
        gap: "6px",
        color: "#424a3f",
        fontSize: "13px",
        fontWeight: 700,
    },
    input: {
        width: "100%",
        minHeight: "38px",
        border: "1px solid #c9d0bd",
        borderRadius: "8px",
        padding: "8px 10px",
        background: "#ffffff",
        color: "#202820",
        outline: "none",
    },
    contentGrid: {
        display: "grid",
        gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 360px), 1fr))",
        gap: "16px",
        alignItems: "start",
    },
    listPanel: {
        border: "1px solid #d5dbc8",
        borderRadius: "8px",
        background: "#ffffff",
        minHeight: "520px",
        overflow: "hidden",
    },
    detailPanel: {
        border: "1px solid #d5dbc8",
        borderRadius: "8px",
        background: "#ffffff",
        minHeight: "520px",
        padding: "18px",
    },
    panelHeader: {
        display: "flex",
        justifyContent: "space-between",
        alignItems: "center",
        padding: "14px",
        borderBottom: "1px solid #e3e7da",
    },
    panelTitle: {
        margin: 0,
        fontSize: "18px",
    },
    mutedText: {
        margin: 0,
        color: "#66705f",
        fontSize: "13px",
        lineHeight: 1.45,
    },
    emptyState: {
        padding: "18px",
        color: "#66705f",
        lineHeight: 1.5,
    },
    submissionList: {
        display: "grid",
        gap: "8px",
        padding: "10px",
        maxHeight: "calc(100vh - 310px)",
        overflow: "auto",
    },
    submissionItem: {
        width: "100%",
        display: "grid",
        gap: "6px",
        textAlign: "left",
        border: "1px solid #e1e5d9",
        borderRadius: "8px",
        padding: "12px",
        background: "#ffffff",
        color: "#202820",
        cursor: "pointer",
    },
    submissionItemSelected: {
        border: "1px solid #71a66a",
        background: "#f0f8ee",
    },
    itemTopLine: {
        display: "flex",
        gap: "8px",
        justifyContent: "space-between",
        alignItems: "center",
    },
    itemTitle: {
        minWidth: 0,
        overflowWrap: "anywhere",
    },
    itemMeta: {
        color: "#5f695a",
        fontSize: "13px",
        overflowWrap: "anywhere",
    },
    statusBadge: {
        flex: "0 0 auto",
        display: "inline-flex",
        alignItems: "center",
        minHeight: "24px",
        border: "1px solid",
        borderRadius: "8px",
        padding: "2px 8px",
        fontSize: "12px",
        fontWeight: 800,
        whiteSpace: "nowrap",
    },
    detailHeader: {
        display: "flex",
        justifyContent: "space-between",
        gap: "16px",
        alignItems: "flex-start",
        marginBottom: "16px",
    },
    detailTitle: {
        margin: "0 0 6px",
        fontSize: "24px",
        lineHeight: 1.25,
        overflowWrap: "anywhere",
    },
    metaGrid: {
        display: "grid",
        gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
        gap: "10px",
        marginBottom: "16px",
    },
    infoCell: {
        border: "1px solid #e1e5d9",
        borderRadius: "8px",
        padding: "10px",
        background: "#fbfcf8",
        minWidth: 0,
    },
    infoLabel: {
        display: "block",
        color: "#66705f",
        fontSize: "12px",
        fontWeight: 700,
        marginBottom: "5px",
    },
    infoValue: {
        display: "block",
        color: "#202820",
        fontSize: "13px",
        overflowWrap: "anywhere",
    },
    noteBox: {
        border: "1px solid #e1e5d9",
        borderRadius: "8px",
        padding: "12px",
        marginBottom: "16px",
        background: "#fbfcf8",
    },
    noteText: {
        margin: "6px 0 0",
        color: "#40483c",
        lineHeight: 1.5,
        overflowWrap: "anywhere",
    },
    dataActions: {
        display: "flex",
        justifyContent: "flex-end",
        marginBottom: "16px",
    },
    secondaryButton: {
        minHeight: "38px",
        border: "1px solid #c7cebc",
        borderRadius: "8px",
        padding: "8px 14px",
        background: "#ffffff",
        color: "#2a3326",
        fontWeight: 800,
        cursor: "pointer",
    },
    sectionHeading: {
        margin: "18px 0 10px",
        fontSize: "18px",
    },
    summaryGrid: {
        display: "grid",
        gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))",
        gap: "10px",
        marginBottom: "12px",
    },
    operationGrid: {
        display: "grid",
        gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
        gap: "10px",
    },
    operationBlock: {
        border: "1px solid #e1e5d9",
        borderRadius: "8px",
        padding: "12px",
        background: "#fbfcf8",
    },
    operationRows: {
        display: "flex",
        flexWrap: "wrap",
        gap: "8px",
        marginTop: "10px",
    },
    operationPill: {
        border: "1px solid #cfd8c2",
        borderRadius: "8px",
        padding: "4px 8px",
        background: "#ffffff",
        color: "#394136",
        fontSize: "13px",
    },
    previewGrid: {
        display: "grid",
        gridTemplateColumns: "minmax(min(100%, 420px), 1fr) minmax(min(100%, 260px), 320px)",
        gap: "12px",
        marginBottom: "16px",
        alignItems: "stretch",
    },
    mapPreview: {
        height: "420px",
        minHeight: "320px",
        border: "1px solid #d5dbc8",
        borderRadius: "8px",
        overflow: "hidden",
        background: "#0b1220",
    },
    featurePanel: {
        border: "1px solid #e1e5d9",
        borderRadius: "8px",
        padding: "12px",
        background: "#fbfcf8",
        minWidth: 0,
    },
    featureDetails: {
        display: "grid",
        gap: "8px",
        marginTop: "10px",
    },
    reviewActions: {
        display: "flex",
        justifyContent: "flex-end",
        gap: "10px",
        marginTop: "22px",
        paddingTop: "16px",
        borderTop: "1px solid #e3e7da",
    },
    dangerButton: {
        minHeight: "40px",
        border: "1px solid #a93322",
        borderRadius: "8px",
        padding: "8px 16px",
        background: "#b94330",
        color: "#ffffff",
        fontWeight: 800,
        cursor: "pointer",
    },
    approveButton: {
        minHeight: "40px",
        border: "1px solid #276131",
        borderRadius: "8px",
        padding: "8px 16px",
        background: "#2f7a3b",
        color: "#ffffff",
        fontWeight: 800,
        cursor: "pointer",
    },
    jsonOverlay: {
        position: "fixed",
        inset: 0,
        zIndex: 1000,
        padding: "24px",
        background: "rgba(31, 36, 31, 0.72)",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
    },
    jsonDialog: {
        width: "min(980px, calc(100vw - 48px))",
        maxHeight: "min(760px, calc(100vh - 48px))",
        border: "1px solid #9da891",
        borderRadius: "8px",
        background: "#ffffff",
        color: "#1f241f",
        boxShadow: "0 24px 70px rgba(0, 0, 0, 0.32)",
        display: "flex",
        flexDirection: "column",
        overflow: "hidden",
    },
    jsonDialogHeader: {
        display: "flex",
        alignItems: "flex-start",
        justifyContent: "space-between",
        gap: "16px",
        padding: "14px 16px",
        borderBottom: "1px solid #dfe5d6",
        background: "#f7f8f3",
    },
    jsonDialogTitle: {
        margin: "0 0 5px",
        fontSize: "18px",
        overflowWrap: "anywhere",
    },
    jsonDialogSubtitle: {
        margin: 0,
        color: "#66705f",
        fontSize: "13px",
    },
    jsonCloseButton: {
        minHeight: "34px",
        border: "1px solid #c7cebc",
        borderRadius: "8px",
        padding: "7px 12px",
        background: "#ffffff",
        color: "#2a3326",
        fontWeight: 800,
        cursor: "pointer",
    },
    jsonPre: {
        margin: 0,
        padding: "16px",
        overflow: "auto",
        background: "#10140f",
        color: "#edf7e7",
        fontSize: "12px",
        lineHeight: 1.55,
        fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
        tabSize: 2,
    },
};
