"use client";

import { useState, useEffect, useCallback, useRef } from "react";
import { useStorage } from "@/core/storage";
import { v4 as uuid } from "uuid";
import type {
  RegistryEntry,
  RegistryDirection,
  RegistryStatus,
  DocumentType,
  TrackedDeadline,
  DeadlineResolution,
} from "../types";
import {
  getAllEntries,
  getFullEntry,
  saveEntry,
} from "../services/registry-service";
import type { RegistryAuditEvent } from "../types";
import {
  createTrackedDeadline,
  resolveDeadline as resolveDeadlineFn,
} from "../services/deadline-service";
import { getDeadlineType } from "../services/deadline-catalog";

export interface RegistryFilters {
  search: string;
  direction: RegistryDirection | "all";
  status: RegistryStatus | "all";
  documentType: DocumentType | "all";
  company: string;
}

export function useRegistry() {
  const storage = useStorage("registratura");
  const blobStorage = useStorage("registratura-blobs");
  const [entries, setEntries] = useState<RegistryEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [filters, setFilters] = useState<RegistryFilters>({
    search: "",
    direction: "all",
    status: "all",
    documentType: "all",
    company: "all",
  });
  const migrationRan = useRef(false);

  const refresh = useCallback(async () => {
    setLoading(true);
    const items = await getAllEntries(storage);
    setEntries(items);
    setLoading(false);
  }, [storage]);

  // On mount: trigger server-side blob migration (fire-and-forget), then load list
  // eslint-disable-next-line react-hooks/set-state-in-effect
  useEffect(() => {
    const init = async () => {
      // Trigger server-side migration (runs inside Node.js, not browser)
      if (!migrationRan.current) {
        migrationRan.current = true;
        fetch("/api/storage/migrate-blobs", { method: "POST" }).catch(() => {});
      }
      await refresh();
    };
    init();
  }, [refresh]);

  const addEntry = useCallback(
    async (
      data: Omit<RegistryEntry, "id" | "number" | "createdAt" | "updatedAt">,
    ) => {
      // Use the API for atomic server-side numbering + audit
      const res = await fetch("/api/registratura", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ entry: data }),
      });
      const result = await res.json();

      if (!result.success) {
        throw new Error(result.error ?? "Failed to create entry");
      }

      const entry = result.entry as RegistryEntry;
      setEntries((prev) => [entry, ...prev]);
      return entry;
    },
    [],
  );

  const updateEntry = useCallback(
    async (id: string, updates: Partial<RegistryEntry>) => {
      // Use the API for server-side diff audit
      const res = await fetch("/api/registratura", {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ id, updates }),
      });
      const result = await res.json();

      if (!result.success) {
        throw new Error(result.error ?? "Failed to update entry");
      }

      await refresh();
    },
    [refresh],
  );

  const removeEntry = useCallback(
    async (id: string) => {
      // Use the API for sequence validation + audit logging
      const res = await fetch(`/api/registratura?id=${encodeURIComponent(id)}`, {
        method: "DELETE",
      });
      const result = await res.json();

      if (!result.success) {
        throw new Error(result.error ?? "Failed to delete entry");
      }

      await refresh();
    },
    [refresh],
  );

  const closeEntry = useCallback(
    async (id: string, closeLinked: boolean) => {
      const entry = entries.find((e) => e.id === id);
      if (!entry) return;
      const now = new Date().toISOString();

      // Auto-resolve all pending deadlines when closing an entry
      const resolvedDeadlines = (entry.trackedDeadlines ?? []).map((dl) => {
        if (dl.resolution === "pending") {
          return resolveDeadlineFn(dl, "completed", "Rezolvat automat la închiderea înregistrării");
        }
        return dl;
      });

      const closedMain: RegistryEntry = {
        ...entry,
        status: "inchis",
        trackedDeadlines: resolvedDeadlines,
        updatedAt: now,
      };
      await saveEntry(storage, blobStorage, closedMain);
      const linked = entry.linkedEntryIds ?? [];
      if (closeLinked && linked.length > 0) {
        const saves = linked
          .map((linkedId) => entries.find((e) => e.id === linkedId))
          .filter((e): e is RegistryEntry => !!e && e.status !== "inchis")
          .map((e) => {
            const resolvedDls = (e.trackedDeadlines ?? []).map((dl) =>
              dl.resolution === "pending"
                ? resolveDeadlineFn(dl, "completed", "Rezolvat automat la închiderea înregistrării")
                : dl,
            );
            return saveEntry(storage, blobStorage, {
              ...e,
              status: "inchis",
              trackedDeadlines: resolvedDls,
              updatedAt: now,
            });
          });
        await Promise.all(saves);
      }
      await refresh();
    },
    [entries, storage, blobStorage, refresh],
  );

  const updateFilter = useCallback(
    <K extends keyof RegistryFilters>(key: K, value: RegistryFilters[K]) => {
      setFilters((prev) => ({ ...prev, [key]: value }));
    },
    [],
  );

  // ── Deadline operations ──

  const addDeadline = useCallback(
    async (
      entryId: string,
      typeId: string,
      startDate: string,
      chainParentId?: string,
    ) => {
      const entry = entries.find((e) => e.id === entryId);
      if (!entry) return null;
      const tracked = createTrackedDeadline(typeId, startDate, chainParentId);
      if (!tracked) return null;
      const existing = entry.trackedDeadlines ?? [];
      const updated: RegistryEntry = {
        ...entry,
        trackedDeadlines: [...existing, tracked],
        updatedAt: new Date().toISOString(),
      };
      await saveEntry(storage, blobStorage, updated);
      await refresh();
      return tracked;
    },
    [entries, storage, blobStorage, refresh],
  );

  const resolveDeadline = useCallback(
    async (
      entryId: string,
      deadlineId: string,
      resolution: DeadlineResolution,
      note?: string,
    ): Promise<TrackedDeadline | null> => {
      const entry = entries.find((e) => e.id === entryId);
      if (!entry) return null;
      const deadlines = entry.trackedDeadlines ?? [];
      const idx = deadlines.findIndex((d) => d.id === deadlineId);
      if (idx === -1) return null;
      const dl = deadlines[idx];
      if (!dl) return null;
      const resolved = resolveDeadlineFn(dl, resolution, note);
      const updatedDeadlines = [...deadlines];
      updatedDeadlines[idx] = resolved;
      const updated: RegistryEntry = {
        ...entry,
        trackedDeadlines: updatedDeadlines,
        updatedAt: new Date().toISOString(),
      };
      await saveEntry(storage, blobStorage, updated);

      const def = getDeadlineType(dl.typeId);
      await refresh();

      if (
        def?.chainNextTypeId &&
        (resolution === "completed" || resolution === "aprobat-tacit")
      ) {
        return resolved;
      }

      return resolved;
    },
    [entries, storage, blobStorage, refresh],
  );

  const removeDeadline = useCallback(
    async (entryId: string, deadlineId: string) => {
      const entry = entries.find((e) => e.id === entryId);
      if (!entry) return;
      const deadlines = entry.trackedDeadlines ?? [];
      const updated: RegistryEntry = {
        ...entry,
        trackedDeadlines: deadlines.filter((d) => d.id !== deadlineId),
        updatedAt: new Date().toISOString(),
      };
      await saveEntry(storage, blobStorage, updated);
      await refresh();
    },
    [entries, storage, blobStorage, refresh],
  );

  const filteredEntries = entries.filter((entry) => {
    if (filters.direction !== "all" && entry.direction !== filters.direction)
      return false;
    if (filters.status !== "all" && entry.status !== filters.status)
      return false;
    if (
      filters.documentType !== "all" &&
      entry.documentType !== filters.documentType
    )
      return false;
    if (filters.company !== "all" && entry.company !== filters.company)
      return false;
    if (filters.search) {
      const q = filters.search.toLowerCase();
      return (
        entry.subject.toLowerCase().includes(q) ||
        entry.sender.toLowerCase().includes(q) ||
        entry.recipient.toLowerCase().includes(q) ||
        entry.number.toLowerCase().includes(q)
      );
    }
    return true;
  });

  const loadFullEntry = useCallback(
    async (id: string): Promise<RegistryEntry | null> => {
      return getFullEntry(storage, blobStorage, id);
    },
    [storage, blobStorage],
  );

  // ── Reserved slots ──

  const createReservedSlots = useCallback(
    async (company: string, year: number, month: number) => {
      const res = await fetch("/api/registratura/reserved", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ company, year, month }),
      });
      const result = await res.json();
      if (result.success) await refresh();
      return result;
    },
    [refresh],
  );

  // ── Audit trail ──

  const loadAuditHistory = useCallback(
    async (entryId: string): Promise<RegistryAuditEvent[]> => {
      const res = await fetch(
        `/api/registratura/audit?entryId=${encodeURIComponent(entryId)}`,
      );
      const result = await res.json();
      return result.events ?? [];
    },
    [],
  );

  return {
    entries: filteredEntries,
    allEntries: entries,
    loading,
    filters,
    updateFilter,
    addEntry,
    updateEntry,
    removeEntry,
    closeEntry,
    loadFullEntry,
    addDeadline,
    resolveDeadline,
    removeDeadline,
    createReservedSlots,
    loadAuditHistory,
    refresh,
  };
}
