"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useRef, useState, useTransition } from "react";

import { BulkDeleteButton } from "@/components/admin/common/BulkDeleteButton";
import { getTierAdminLabel } from "@/lib/module-formatters";
import { ModalPortal } from "@/components/admin/common/ModalPortal";

type ConversionProgress = {
  total: number;
  /** Optimistic ticker value 0..total — increments while the request is in-flight. */
  optimistic: number;
  status: "running" | "done" | "error";
  converted?: number;
  skipped?: number;
  failures?: Array<{ id: string; companyName: string; reason: string }>;
  errorMessage?: string;
};

type SubmissionRow = {
  id: string;
  companyName: string;
  listingTypeLabel: string;
  cityName: string;
  status: "NEW" | "IN_REVIEW" | "WAITING_PAYMENT" | "APPROVED" | "REJECTED";
  selectedPlanId: string;
  planName: string;
  createdAtLabel: string;
  convertedAdminHref?: string | null;
  convertedCompanyName?: string | null;
};

type PlanOption = {
  id: string;
  name: string;
  tier: string;
};

type SubmissionListManagerProps = {
  items: SubmissionRow[];
  plans: PlanOption[];
};

const SUBMISSION_STATUS_OPTIONS = [
  "NEW",
  "IN_REVIEW",
  "WAITING_PAYMENT",
  "APPROVED",
  "REJECTED",
] as const;

const STATUS_LABELS: Record<SubmissionRow["status"], string> = {
  NEW: "Novo",
  IN_REVIEW: "U obradi",
  WAITING_PAYMENT: "Čeka uplatu",
  APPROVED: "Odobreno",
  REJECTED: "Odbijeno",
};

function createNextRows(
  rows: SubmissionRow[],
  ids: string[],
  changes: Partial<Pick<SubmissionRow, "status" | "selectedPlanId" | "planName">>,
) {
  const touched = new Set(ids);
  return rows.map((row) => (touched.has(row.id) ? { ...row, ...changes } : row));
}

export function SubmissionListManager({
  items: initialItems,
  plans,
}: SubmissionListManagerProps) {
  const router = useRouter();
  const [items, setItems] = useState(initialItems);
  const [selectedIds, setSelectedIds] = useState<string[]>([]);
  const [message, setMessage] = useState<string | null>(null);
  const [bulkStatus, setBulkStatus] = useState("");
  const [bulkPlanId, setBulkPlanId] = useState("");
  const [isPending, startTransition] = useTransition();
  const [progress, setProgress] = useState<ConversionProgress | null>(null);
  const progressTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    return () => {
      if (progressTimerRef.current) {
        clearInterval(progressTimerRef.current);
        progressTimerRef.current = null;
      }
    };
  }, []);

  function startProgress(total: number) {
    if (progressTimerRef.current) {
      clearInterval(progressTimerRef.current);
    }
    setProgress({ total, optimistic: 0, status: "running" });
    progressTimerRef.current = setInterval(() => {
      setProgress((current) => {
        if (!current || current.status !== "running") return current;
        // ramp up to ~90% while in flight; settle on actual result on completion
        const ceiling = Math.max(1, Math.floor(current.total * 0.9));
        if (current.optimistic >= ceiling) return current;
        return { ...current, optimistic: current.optimistic + 1 };
      });
    }, 500);
  }

  function finishProgress(patch: Partial<ConversionProgress>) {
    if (progressTimerRef.current) {
      clearInterval(progressTimerRef.current);
      progressTimerRef.current = null;
    }
    setProgress((current) => (current ? { ...current, ...patch } : current));
  }

  function buildFailuresCsv(failures: NonNullable<ConversionProgress["failures"]>) {
    const header = "id,companyName,reason";
    const lines = failures.map((f) => {
      const esc = (v: string) => `"${v.replace(/"/g, '""')}"`;
      return [esc(f.id), esc(f.companyName), esc(f.reason)].join(",");
    });
    return `﻿${[header, ...lines].join("\r\n")}`;
  }

  function downloadFailuresCsv() {
    if (!progress?.failures?.length) return;
    const blob = new Blob([buildFailuresCsv(progress.failures)], {
      type: "text/csv;charset=utf-8",
    });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `bulk-konverzija-greske_${new Date().toISOString().slice(0, 10)}.csv`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  }

  const allSelected = items.length > 0 && selectedIds.length === items.length;
  const hasBulkChanges = Boolean(bulkStatus || bulkPlanId);

  function toggleSelection(id: string) {
    setSelectedIds((current) =>
      current.includes(id) ? current.filter((item) => item !== id) : [...current, id],
    );
  }

  function toggleAll() {
    setSelectedIds(allSelected ? [] : items.map((item) => item.id));
  }

  async function submitBulkUpdate(
    ids: string[],
    changes: {
      status?: SubmissionRow["status"];
      selectedPlanId?: string | null;
    },
    successMessage: string,
  ) {
    const response = await fetch("/api/admin/submissions/bulk", {
      method: "POST",
      headers: {
        "content-type": "application/json",
      },
      body: JSON.stringify({
        ids,
        changes,
      }),
    });

    const payload = (await response.json()) as { message?: string };
    if (!response.ok) {
      throw new Error(payload.message || "Bulk izmena prijava nije uspela.");
    }

    const planName =
      changes.selectedPlanId === undefined
        ? undefined
        : changes.selectedPlanId
          ? plans.find((plan) => plan.id === changes.selectedPlanId)?.name || ""
          : "Bez plana";

    setItems((current) =>
      createNextRows(current, ids, {
        ...(changes.status ? { status: changes.status } : {}),
        ...(changes.selectedPlanId !== undefined
          ? {
              selectedPlanId: changes.selectedPlanId || "",
              planName: planName ?? "",
            }
          : {}),
      }),
    );
    setMessage(successMessage);
    router.refresh();
  }

  async function submitBulkConvert(ids: string[], successMessage: string) {
    startProgress(ids.length);
    const response = await fetch("/api/admin/submissions/convert", {
      method: "POST",
      headers: {
        "content-type": "application/json",
      },
      body: JSON.stringify({
        ids,
      }),
    });

    const payload = (await response.json()) as {
      message?: string;
      converted?: number;
      skipped?: number;
      items?: Array<{
        id: string;
        name: string;
        type: "COMPANY" | "PLACE" | "AGENCY";
      }>;
    };

    if (!response.ok) {
      finishProgress({
        status: "error",
        errorMessage: payload.message || "Konverzija prijava nije uspela.",
      });
      throw new Error(payload.message || "Konverzija prijava nije uspela.");
    }

    const createdMap = new Map((payload.items ?? []).map((item) => [item.name, item]));
    const failures = ids
      .filter((id) => {
        const row = items.find((r) => r.id === id);
        return row ? !createdMap.has(row.companyName) : false;
      })
      .map((id) => {
        const row = items.find((r) => r.id === id);
        return {
          id,
          companyName: row?.companyName ?? id,
          reason: "Backend nije vratio kreirani profil (verovatno duplikat ili validacija).",
        };
      });

    finishProgress({
      status: "done",
      optimistic: ids.length,
      converted: payload.converted ?? 0,
      skipped: payload.skipped ?? 0,
      failures,
    });
    setItems((current) =>
      current.map((item) => {
        if (!ids.includes(item.id)) {
          return item;
        }

        const created = createdMap.get(item.companyName);
        if (!created) {
          return {
            ...item,
            status: "APPROVED",
          };
        }

        return {
          ...item,
          status: "APPROVED",
          convertedCompanyName: created.name,
          convertedAdminHref:
            created.type === "PLACE"
              ? `/admin/mesta/${created.id}`
              : `/admin/kompanije/${created.id}`,
        };
      }),
    );
    setMessage(
      `${successMessage} Konvertovano: ${payload.converted ?? 0}, preskočeno: ${payload.skipped ?? 0}.`,
    );
    router.refresh();
  }

  function handleBulkApply() {
    const changes: {
      status?: SubmissionRow["status"];
      selectedPlanId?: string | null;
    } = {};

    if (bulkStatus) {
      changes.status = bulkStatus as SubmissionRow["status"];
    }

    if (bulkPlanId) {
      changes.selectedPlanId = bulkPlanId === "__NONE__" ? null : bulkPlanId;
    }

    startTransition(async () => {
      try {
        await submitBulkUpdate(
          selectedIds,
          changes,
          `Masovna izmena je sačuvana za ${selectedIds.length} prijava.`,
        );
      } catch (error) {
        setMessage(error instanceof Error ? error.message : "Masovna izmena prijava nije uspela.");
      }
    });
  }

  function handleInlineUpdate(
    id: string,
    changes: {
      status?: SubmissionRow["status"];
      selectedPlanId?: string | null;
    },
    successMessage: string,
  ) {
    startTransition(async () => {
      try {
        await submitBulkUpdate([id], changes, successMessage);
      } catch (error) {
        setMessage(error instanceof Error ? error.message : "Inline izmena prijave nije uspela.");
      }
    });
  }

  function handleConvert(ids: string[], successMessage: string) {
    startTransition(async () => {
      try {
        await submitBulkConvert(ids, successMessage);
        setSelectedIds((current) => current.filter((id) => !ids.includes(id)));
      } catch (error) {
        setMessage(error instanceof Error ? error.message : "Konverzija prijave nije uspela.");
      }
    });
  }

  return (
    <div className="admin-toolbar overflow-hidden rounded-[2rem]">
      <div className="flex flex-col gap-4 border-b border-border px-5 py-4 xl:flex-row xl:items-center xl:justify-between">
        <div className="flex flex-wrap items-center gap-3">
          <span className="admin-chip">Ukupno: {items.length}</span>
          <span className="admin-chip">Označeno: {selectedIds.length}</span>
        </div>
        <div className="text-sm text-muted-foreground">
          Status, plan i konverzija u profil sada rade direktno iz inbox liste.
        </div>
      </div>

      <div className="border-b border-border px-5 py-4">
        <div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto]">
          <select
            value={bulkStatus}
            onChange={(event) => setBulkStatus(event.target.value)}
            aria-label="Bulk status za prijave"
            className="inline-select"
          >
            <option value="">Bulk status</option>
            {SUBMISSION_STATUS_OPTIONS.map((status) => (
              <option key={status} value={status}>
                {STATUS_LABELS[status]}
              </option>
            ))}
          </select>
          <select
            value={bulkPlanId}
            onChange={(event) => setBulkPlanId(event.target.value)}
            aria-label="Bulk plan za prijave"
            className="inline-select"
          >
            <option value="">Bulk plan</option>
            <option value="__NONE__">Bez plana</option>
            {plans.map((plan) => (
              <option key={plan.id} value={plan.id}>
                {plan.name} · {getTierAdminLabel(plan.tier)}
              </option>
            ))}
          </select>
          <button
            type="button"
            onClick={handleBulkApply}
            disabled={isPending || selectedIds.length === 0 || !hasBulkChanges}
            className="primary-button"
          >
            {isPending ? "Čuvanje..." : "Primeni na označene"}
          </button>
          <button
            type="button"
            onClick={() => handleConvert(selectedIds, "Bulk konverzija prijava je završena.")}
            disabled={isPending || selectedIds.length === 0}
            className="ghost-button"
          >
            Pretvori u profile
          </button>
          <BulkDeleteButton
            endpoint="/api/admin/submissions/bulk"
            ids={selectedIds}
            itemLabel="prijava"
            onDeleted={(ids) => {
              setItems((current) => current.filter((row) => !ids.includes(row.id)));
              setSelectedIds([]);
              router.refresh();
            }}
          />
        </div>
        {message ? <p className="mt-3 text-sm text-muted-foreground">{message}</p> : null}
      </div>

      <div className="overflow-x-auto">
          <table className="admin-data-table text-left">
          <thead className="bg-white/75">
            <tr>
              <th className="px-5 py-4">
                <input
                  type="checkbox"
                  checked={allSelected}
                  onChange={toggleAll}
                  aria-label="Označi sve prijave"
                />
              </th>
              {["Prijava", "Grad", "Plan", "Status", "Primljeno", "Profil", "Akcija"].map(
                (column) => (
                  <th
                    key={column}
                    className="px-5 py-4 text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground"
                  >
                    {column}
                  </th>
                ),
              )}
            </tr>
          </thead>
          <tbody className="divide-y divide-border/70">
            {items.map((item) => (
              <tr key={item.id} className="bg-white/55">
                <td className="px-5 py-4 align-top">
                  <input
                    type="checkbox"
                    checked={selectedIds.includes(item.id)}
                    onChange={() => toggleSelection(item.id)}
                    aria-label={`Označi ${item.companyName}`}
                  />
                </td>
                <td className="px-5 py-4 align-top">
                  <div className="min-w-[240px]">
                    <div className="font-semibold text-foreground">{item.companyName}</div>
                    <div className="mt-1 text-xs uppercase tracking-[0.14em] text-muted-foreground">
                      {item.listingTypeLabel}
                    </div>
                  </div>
                </td>
                <td className="px-5 py-4 align-top text-sm text-foreground">
                  {item.cityName || "N/A"}
                </td>
                <td className="px-5 py-4 align-top">
                  <select
                    value={item.selectedPlanId}
                    onChange={(event) =>
                      handleInlineUpdate(
                        item.id,
                        { selectedPlanId: event.target.value || null },
                        `Plan je ažuriran za prijavu ${item.companyName}.`,
                      )
                    }
                    disabled={isPending}
                    aria-label={`Plan za prijavu ${item.companyName}`}
                    className="inline-select"
                  >
                    <option value="">Bez plana</option>
                    {plans.map((plan) => (
                      <option key={plan.id} value={plan.id}>
                        {plan.name} · {getTierAdminLabel(plan.tier)}
                      </option>
                    ))}
                  </select>
                  <div className="mt-2 text-xs text-muted-foreground">
                    {item.planName || "Bez plana"}
                  </div>
                </td>
                <td className="px-5 py-4 align-top">
                  <select
                    value={item.status}
                    onChange={(event) =>
                      handleInlineUpdate(
                        item.id,
                        { status: event.target.value as SubmissionRow["status"] },
                        `Status je ažuriran za prijavu ${item.companyName}.`,
                      )
                    }
                    disabled={isPending}
                    aria-label={`Status za prijavu ${item.companyName}`}
                    className="inline-select"
                  >
                    {SUBMISSION_STATUS_OPTIONS.map((status) => (
                      <option key={status} value={status}>
                        {STATUS_LABELS[status]}
                      </option>
                    ))}
                  </select>
                </td>
                <td className="px-5 py-4 align-top text-sm text-foreground">
                  {item.createdAtLabel}
                </td>
                <td className="px-5 py-4 align-top text-sm text-foreground">
                  {item.convertedAdminHref ? (
                    <Link href={item.convertedAdminHref} className="ghost-button px-4 py-2 text-sm">
                      {item.convertedCompanyName || "Otvori profil"}
                    </Link>
                  ) : (
                    <span className="text-muted-foreground">Nije pretvoreno</span>
                  )}
                </td>
                <td className="px-5 py-4 align-top">
                  <div className="admin-table-actions">
                    <Link href={`/admin/prijave/${item.id}`} className="admin-table-ghost-btn">
                      Otvori
                    </Link>
                    {!item.convertedAdminHref ? (
                      <button
                        type="button"
                        onClick={() =>
                          handleConvert([item.id], `Prijava ${item.companyName} je pretvorena u profil.`)
                        }
                        disabled={isPending}
                        className="admin-table-ghost-btn"
                        style={{ background: "linear-gradient(180deg, #f97552, #c2410c)", color: "#ffffff", borderColor: "transparent" }}
                      >
                        Pretvori
                      </button>
                    ) : null}
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {progress ? (
        <ModalPortal>
        <div
          role="dialog"
          aria-modal="true"
          aria-label="Bulk konverzija prijava"
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 px-4"
        >
          <div className="surface w-full max-w-md rounded-[1.75rem] p-6">
            {progress.status === "running" ? (
              <>
                <h3 className="font-display text-2xl font-semibold text-foreground">
                  Konvertujem {progress.total}{" "}
                  {progress.total === 1 ? "prijavu" : "prijava"}…
                </h3>
                <p className="mt-2 text-sm text-muted-foreground">
                  Ovo može potrajati za veće serije. Ne zatvaraj ovaj prozor.
                </p>
                <div
                  className="mt-5 h-2 w-full overflow-hidden rounded-full bg-border/60"
                  role="progressbar"
                  aria-valuemin={0}
                  aria-valuemax={progress.total}
                  aria-valuenow={progress.optimistic}
                >
                  <div
                    className="h-full bg-primary transition-[width] duration-500"
                    style={{
                      width: `${Math.min(100, Math.round((progress.optimistic / Math.max(1, progress.total)) * 100))}%`,
                    }}
                  />
                </div>
                <div className="mt-2 text-xs text-muted-foreground">
                  {progress.optimistic} / {progress.total}
                </div>
              </>
            ) : progress.status === "error" ? (
              <>
                <h3 className="font-display text-2xl font-semibold text-rose-600">
                  Greška u konverziji
                </h3>
                <p className="mt-2 text-sm text-muted-foreground">
                  {progress.errorMessage || "Bulk konverzija nije uspela."}
                </p>
                <div className="mt-5 flex justify-end">
                  <button
                    type="button"
                    onClick={() => setProgress(null)}
                    className="primary-button"
                  >
                    Zatvori
                  </button>
                </div>
              </>
            ) : (
              <>
                <h3 className="font-display text-2xl font-semibold text-foreground">
                  Konverzija završena
                </h3>
                <dl className="mt-4 grid grid-cols-3 gap-3 text-center">
                  <div className="rounded-2xl border border-border bg-white/70 p-3">
                    <dt className="text-xs uppercase tracking-[0.14em] text-muted-foreground">
                      Konvertovano
                    </dt>
                    <dd className="mt-1 text-xl font-semibold text-emerald-600">
                      {progress.converted ?? 0}
                    </dd>
                  </div>
                  <div className="rounded-2xl border border-border bg-white/70 p-3">
                    <dt className="text-xs uppercase tracking-[0.14em] text-muted-foreground">
                      Preskočeno
                    </dt>
                    <dd className="mt-1 text-xl font-semibold text-amber-600">
                      {progress.skipped ?? 0}
                    </dd>
                  </div>
                  <div className="rounded-2xl border border-border bg-white/70 p-3">
                    <dt className="text-xs uppercase tracking-[0.14em] text-muted-foreground">
                      Greške
                    </dt>
                    <dd className="mt-1 text-xl font-semibold text-rose-600">
                      {progress.failures?.length ?? 0}
                    </dd>
                  </div>
                </dl>
                <div className="mt-5 flex flex-wrap justify-end gap-2">
                  {progress.failures && progress.failures.length > 0 ? (
                    <button
                      type="button"
                      onClick={downloadFailuresCsv}
                      className="ghost-button"
                    >
                      Preuzmi CSV grešaka
                    </button>
                  ) : null}
                  <button
                    type="button"
                    onClick={() => setProgress(null)}
                    className="primary-button"
                  >
                    Zatvori
                  </button>
                </div>
              </>
            )}
          </div>
        </div>
        </ModalPortal>
      ) : null}
    </div>
  );
}
