// components/lists/CO2GalvoList.tsx
"use client";

import { useEffect, useMemo, useState } from "react";
import Link from "next/link";

type Owner =
| string
| number
| {
    id?: string | number;
    username?: string | null;
    first_name?: string | null;
    last_name?: string | null;
    email?: string | null;
}
| null
| undefined;

type SettingsRow = {
    submission_id: string | number;
    setting_title?: string | null;
    uploader?: string | null;
    owner?: Owner;
    mat?: { name?: string | null } | null;
    mat_coat?: { name?: string | null } | null;
    source?: { model?: string | null } | null;
    lens?: { field_size?: string | number | null } | null;
};

export type CO2GalvoListProps = {
    /** Build the href for a record (portal vs standalone) */
    linkFor: (submission_id: string | number, opts?: { edit?: boolean }) => string;
    /** Optional controlled search text (else internal input) */
    queryText?: string;
    onQueryChange?: (q: string) => void;
};

async function readJson(res: Response) {
    const text = await res.text();
    try {
        return text ? JSON.parse(text) : null;
    } catch {
        throw new Error(`Unexpected response (status ${res.status})`);
    }
}

export default function CO2GalvoList({ linkFor, queryText, onQueryChange }: CO2GalvoListProps) {
    const [settings, setSettings] = useState<SettingsRow[]>([]);
    const [ownerMap, setOwnerMap] = useState<Record<string, string>>({});
    const [loading, setLoading] = useState(true);
    const [resolvingOwners, setResolvingOwners] = useState(false);
    const [meId, setMeId] = useState<string | null>(null);
    const [localQuery, setLocalQuery] = useState(queryText ?? "");

    // keep local and external search text in sync
    useEffect(() => {
        if (queryText !== undefined) setLocalQuery(queryText);
    }, [queryText]);

        // load current user id (for edit visibility)
        useEffect(() => {
            let dead = false;
            (async () => {
                try {
                    const r = await fetch(`/api/dx/users/me?fields=id`, {
                        cache: "no-store",
                        credentials: "include",
                    });
                    if (!r.ok) return;
                    const j = await readJson(r);
                    const id = j?.data?.id ?? j?.id ?? null;
                    if (!dead) setMeId(id ? String(id) : null);
                } catch {
                    /* ignore */
                }
            })();
            return () => {
                dead = true;
            };
        }, []);

        // load list
        useEffect(() => {
            const fields = [
                "submission_id",
                "setting_title",
                "uploader",
                "owner",
                "owner.id",
                "owner.username",
                "photo.id",
                "photo.title",
                "mat.name",
                "mat_coat.name",
                "source.model",
                "lens.field_size",
            ].join(",");

            const url = `/api/dx/items/settings_co2gal?fields=${encodeURIComponent(fields)}&limit=-1`;

            fetch(url, { cache: "no-store", credentials: "include" })
            .then(async (res) => {
                if (!res.ok) {
                    const j = await readJson(res).catch(() => null);
                    const msg = (j as any)?.errors?.[0]?.message || `HTTP ${res.status}`;
                    throw new Error(msg);
                }
                return readJson(res);
            })
            .then((json: any) => setSettings(Array.isArray(json?.data) ? json.data : []))
            .catch((e) => {
                console.error("CO2 Galvo list fetch failed:", e);
                setSettings([]);
            })
            .finally(() => setLoading(false));
        }, []);

        // resolve owner usernames if needed
        useEffect(() => {
            if (!settings.length) return;

            const ids = new Set<string>();
            for (const s of settings) {
                const o = s.owner;
                if (!o) continue;

                if (typeof o === "string" || typeof o === "number") {
                    const k = String(o);
                    if (!ownerMap[k]) ids.add(k);
                } else {
                    const id = o.id != null ? String(o.id) : "";
                    const hasUsername = !!o.username;
                    if (id && !hasUsername && !ownerMap[id]) ids.add(id);
                }
            }
            if (!ids.size) return;

            const all = Array.from(ids);
            const chunk = 100;
            setResolvingOwners(true);

            (async () => {
                const updates: Record<string, string> = {};
                for (let i = 0; i < all.length; i += chunk) {
                    const slice = all.slice(i, i + chunk);
                    const qs = new URLSearchParams();
                    qs.set("fields", "id,username");
                    qs.set("limit", String(slice.length));
                    qs.set("filter[id][_in]", slice.join(","));

                    try {
                        const r = await fetch(`/api/dx/users?${qs.toString()}`, {
                            credentials: "include",
                            cache: "no-store",
                        });
                        if (!r.ok) {
                            const j = await readJson(r).catch(() => null);
                            const msg = (j as any)?.errors?.[0]?.message || `HTTP ${r.status}`;
                            console.warn("Owner lookup failed:", msg);
                            if (r.status === 401 || r.status === 403) break;
                            continue;
                        }
                        const j = await readJson(r);
                        const rows: Array<{ id: string; username?: string | null }> = j?.data || [];
                        for (const row of rows) {
                            updates[String(row.id)] = row.username || String(row.id);
                        }
                    } catch (e) {
                        console.warn("Owner lookup error:", e);
                        break;
                    }
                }

                if (Object.keys(updates).length) {
                    setOwnerMap((prev) => ({ ...prev, ...updates }));
                }
                setResolvingOwners(false);
            })();
        }, [settings, ownerMap]);

        const isMine = (o: Owner) => {
            if (!meId || !o) return false;
            if (typeof o === "string" || typeof o === "number") return String(o) === meId;
            if (o.id != null) return String(o.id) === meId;
            return false;
        };

        const ownerLabel = (o: Owner) => {
            if (!o) return "—";
            if (typeof o === "string" || typeof o === "number") {
                const id = String(o);
                return ownerMap[id] || id;
            }
            return (
                o.username ||
                [o.first_name, o.last_name].filter(Boolean).join(" ").trim() ||
                o.email ||
                (o.id != null ? String(o.id) : "—")
            );
        };

        const filtered = useMemo(() => {
            const nq = (localQuery || "").toLowerCase();
            if (!nq) return settings;
            return settings.filter((entry) => {
                const fields = [
                    entry.setting_title,
                    ownerLabel(entry.owner),
                                   entry.uploader,
                                   entry.mat?.name,
                                   entry.mat_coat?.name,
                                   entry.source?.model,
                                   entry.lens?.field_size as any,
                ].filter(Boolean);
                return fields.some((v: any) => String(v).toLowerCase().includes(nq));
            });
        }, [settings, localQuery, ownerMap]);

        return (
            <div className="space-y-3">
            <div>
            <input
            value={localQuery}
            onChange={(e) => {
                setLocalQuery(e.currentTarget.value);
                onQueryChange?.(e.currentTarget.value);
            }}
            placeholder="Search by title, owner, material, model…"
            className="w-full border rounded px-3 py-2"
            />
            </div>

            {loading ? (
                <p>Loading…</p>
            ) : (
                <div className="overflow-x-auto">
                <table className="w-full table-fixed text-sm">
                <thead className="sticky top-0">
                <tr className="border-b">
                <th className="px-2 py-2 text-left w-[30%]">Title</th>
                <th className="px-2 py-2 text-left w-[14%]">
                Owner {resolvingOwners ? "…resolving" : ""}
                </th>
                <th className="px-2 py-2 text-left w-[14%]">Material</th>
                <th className="px-2 py-2 text-left w-[14%]">Coating</th>
                <th className="px-2 py-2 text-left w-[14%]">Model</th>
                <th className="px-2 py-2 text-left w-[10%]">Field</th>
                <th className="px-2 py-2 text-left w-[4%]">Edit</th>
                </tr>
                </thead>
                <tbody className="divide-y">
                {filtered.map((s) => {
                    const mine = isMine(s.owner);
                    const ownerText = ownerLabel(s.owner) + (mine ? " (you)" : "");
                    return (
                        <tr key={s.submission_id} className="hover:bg-muted/40">
                        <td className="px-2 py-2 truncate">
                        <Link href={linkFor(s.submission_id)} className="underline">
                        {s.setting_title || "Untitled"}
                        </Link>
                        </td>
                        <td className="px-2 py-2 truncate">{ownerText}</td>
                        <td className="px-2 py-2 truncate">{s.mat?.name || "—"}</td>
                        <td className="px-2 py-2 truncate">{s.mat_coat?.name || "—"}</td>
                        <td className="px-2 py-2 truncate">{s.source?.model || "—"}</td>
                        <td className="px-2 py-2 truncate">{s.lens?.field_size || "—"}</td>
                        <td className="px-2 py-2">
                        {mine ? (
                            <Link href={linkFor(s.submission_id, { edit: true })} className="underline">
                            Edit
                            </Link>
                        ) : (
                            <span className="opacity-50">—</span>
                        )}
                        </td>
                        </tr>
                    );
                })}
                </tbody>
                </table>
                </div>
            )}
            </div>
        );
}
