import { useCallback, useEffect, useMemo, useState } from "react";
import {
  buildArtifactPipelineSummary,
  buildInventoryCatalogSummary,
  buildInventoryRows,
  filterInventoryRows,
  sortInventoryRows,
  type InventoryCatalogSummary,
  type InventoryBrowserFilter,
  type InventoryBrowserRow,
  type InventoryBrowserSort,
  type InventoryPipelineSummary,
} from "../../../lib/inventoryBrowser";
import { buildScanResultPromotionSummary, type ScanResultPromotionSummary } from "../../../lib/scanResultPromotion";
import { createRendererRepositories } from "../../../infrastructure/repositories/rendererBridgeRepositories";
import type { NativeScannerCatalogStatus, NativeScannerDataStatus, NativeScannerReviewArtifactInput } from "../../../types/global";
import type { StoredArtifactRecord, StoredScanResultEntry } from "../../../types/storage";
import type { InventoryViewProps } from "../types";

export interface InventoryViewModel {
  rows: InventoryBrowserRow[];
  selectedRow: InventoryBrowserRow | null;
  selectedPreview: { dataUrl: string; width: number; height: number; path: string } | null;
  previewStatus: string;
  filter: InventoryBrowserFilter;
  sort: InventoryBrowserSort;
  loading: boolean;
  statusText: string;
  promotionStatus: string;
  promotionPending: boolean;
  promotionConfirming: boolean;
  reviewEditing: boolean;
  reviewPending: boolean;
  reviewStatus: string;
  reviewDraft: InventoryReviewDraft | null;
  totalRows: number;
  nativeCount: number;
  storedCount: number;
  reviewCount: number;
  catalogSummary: InventoryCatalogSummary;
  promotionSummary: ScanResultPromotionSummary;
  pipelineSummary: InventoryPipelineSummary;
  filterOptions: Array<{ id: InventoryBrowserFilter; label: string; count: number }>;
  sortOptions: Array<{ id: InventoryBrowserSort; label: string }>;
  setFilter: (filter: InventoryBrowserFilter) => void;
  setSort: (sort: InventoryBrowserSort) => void;
  setSelectedId: (id: string) => void;
  refresh: () => Promise<void>;
  requestSelectedPromotion: () => void;
  cancelSelectedPromotion: () => void;
  confirmSelectedPromotion: () => Promise<void>;
  startSelectedReview: () => void;
  cancelSelectedReview: () => void;
  setReviewDraft: (draft: InventoryReviewDraft) => void;
  submitSelectedReview: (action: "approve" | "reject") => Promise<void>;
}

export interface InventoryReviewDraft {
  name: string;
  slot: string;
  level: string;
  setName: string;
  mainStat: string;
  mainValue: string;
  substats: string;
  equipped: string;
  locked: boolean;
  note: string;
}

export function useInventoryViewModel({ snapshot }: InventoryViewProps): InventoryViewModel {
  const repositories = useMemo(() => createRendererRepositories(), []);
  const [storedArtifacts, setStoredArtifacts] = useState<StoredArtifactRecord[]>([]);
  const [nativeResults, setNativeResults] = useState<StoredScanResultEntry[]>([]);
  const [nativeRunDir, setNativeRunDir] = useState("");
  const [nativeDataStatus, setNativeDataStatus] = useState<NativeScannerDataStatus | null>(null);
  const [nativeCatalog, setNativeCatalog] = useState<NativeScannerCatalogStatus | null>(null);
  const [selectedPreview, setSelectedPreview] = useState<{ dataUrl: string; width: number; height: number; path: string } | null>(null);
  const [previewStatus, setPreviewStatus] = useState("");
  const [filter, setFilter] = useState<InventoryBrowserFilter>("all");
  const [sort, setSort] = useState<InventoryBrowserSort>("newest");
  const [selectedId, setSelectedId] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const [promotionStatus, setPromotionStatus] = useState("");
  const [promotionPending, setPromotionPending] = useState(false);
  const [promotionConfirmingId, setPromotionConfirmingId] = useState("");
  const [reviewEditingId, setReviewEditingId] = useState("");
  const [reviewDraft, setReviewDraft] = useState<InventoryReviewDraft | null>(null);
  const [reviewPending, setReviewPending] = useState(false);
  const [reviewStatus, setReviewStatus] = useState("");

  const refresh = useCallback(async () => {
    setLoading(true);
    setError("");
    try {
      const [artifactResult, nativeResult, dataResult, catalogResult] = await Promise.allSettled([
        repositories?.artifacts.loadAll(),
        repositories?.automation.nativeScannerLoadResults({ limit: 500 }),
        repositories?.automation.nativeScannerDataStatus(),
        repositories?.automation.nativeScannerCatalog(),
      ]);

      if (artifactResult.status === "fulfilled" && artifactResult.value?.ok) {
        setStoredArtifacts(artifactResult.value.artifacts);
      }
      if (nativeResult.status === "fulfilled" && nativeResult.value?.ok) {
        setNativeResults(nativeResult.value.results);
        setNativeRunDir(nativeResult.value.runDir);
      }
      if (dataResult.status === "fulfilled" && dataResult.value?.valid !== undefined) {
        setNativeDataStatus(dataResult.value);
      }
      if (catalogResult.status === "fulfilled" && catalogResult.value?.data?.valid !== undefined) {
        setNativeCatalog(catalogResult.value);
        setNativeDataStatus(catalogResult.value.data);
      }
      if (artifactResult.status === "rejected") {
        setError(errorMessage(artifactResult.reason));
      }
    } finally {
      setLoading(false);
    }
  }, [repositories]);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  const allRows = useMemo(
    () =>
      buildInventoryRows({
        nativeRunDir,
        nativeResults,
        storedArtifacts,
        snapshotArtifacts: snapshot.artifacts,
      }),
    [nativeResults, nativeRunDir, snapshot.artifacts, storedArtifacts],
  );
  const rows = useMemo(
    () => sortInventoryRows(filterInventoryRows(allRows, filter), sort),
    [allRows, filter, sort],
  );
  const selectedRow = rows.find((row) => row.id === selectedId) ?? rows[0] ?? null;
  const promotionConfirming = Boolean(selectedRow && promotionConfirmingId === selectedRow.id);
  const reviewEditing = Boolean(selectedRow && reviewEditingId === selectedRow.id && reviewDraft);

  const requestSelectedPromotion = useCallback(() => {
    if (selectedRow?.canPromote) setPromotionConfirmingId(selectedRow.id);
  }, [selectedRow]);

  const cancelSelectedPromotion = useCallback(() => setPromotionConfirmingId(""), []);

  const confirmSelectedPromotion = useCallback(async () => {
    if (!selectedRow?.canPromote || !selectedRow.runDir || !selectedRow.scanResultId || !repositories?.automation) return;
    setPromotionPending(true);
    setPromotionStatus("Promotion wird geprueft und geschrieben...");
    try {
      const result = await repositories.automation.nativeScannerPromoteResults({
        runDir: selectedRow.runDir,
        resultIds: [selectedRow.scanResultId],
      });
      if (!result.ok) {
        setPromotionStatus(result.error ?? "Promotion wurde blockiert.");
        return;
      }
      setPromotionStatus(`${result.promoted} Ergebnis promotet, ${result.added} neu, ${result.updated} aktualisiert. Log: ${result.logPath}`);
      setPromotionConfirmingId("");
      await refresh();
    } catch (promotionError) {
      setPromotionStatus(errorMessage(promotionError));
    } finally {
      setPromotionPending(false);
    }
  }, [refresh, repositories, selectedRow]);

  const startSelectedReview = useCallback(() => {
    if (!selectedRow || selectedRow.source !== "native" || !selectedRow.needsReview) return;
    setReviewEditingId(selectedRow.id);
    setReviewDraft({
      name: selectedRow.title,
      slot: selectedRow.slot,
      level: selectedRow.levelLabel.replace("+", ""),
      setName: selectedRow.setName,
      mainStat: selectedRow.mainStat,
      mainValue: selectedRow.mainValue,
      substats: selectedRow.substats.join("\n"),
      equipped: selectedRow.equipped,
      locked: Boolean(selectedRow.locked),
      note: "",
    });
  }, [selectedRow]);

  const cancelSelectedReview = useCallback(() => {
    setReviewEditingId("");
    setReviewDraft(null);
  }, []);

  const submitSelectedReview = useCallback(async (action: "approve" | "reject") => {
    if (!selectedRow?.runDir || !selectedRow.scanResultId || !reviewDraft || !repositories?.automation) return;
    setReviewPending(true);
    setReviewStatus(action === "approve" ? "Korrektur wird validiert..." : "Ergebnis wird abgelehnt...");
    try {
      const artifact: NativeScannerReviewArtifactInput = {
        name: reviewDraft.name,
        slot: reviewDraft.slot,
        level: Number(reviewDraft.level),
        setName: reviewDraft.setName,
        mainStat: reviewDraft.mainStat,
        mainValue: reviewDraft.mainValue,
        substats: reviewDraft.substats.split(/\r?\n|;/).map((entry) => entry.trim()).filter(Boolean),
        equipped: reviewDraft.equipped,
        locked: reviewDraft.locked,
      };
      const result = await repositories.automation.nativeScannerReviewResult({
        runDir: selectedRow.runDir,
        resultId: selectedRow.scanResultId,
        action,
        artifact: action === "approve" ? artifact : undefined,
        note: reviewDraft.note,
      });
      if (!result.ok) {
        setReviewStatus(result.error ?? "Review wurde blockiert.");
        return;
      }
      setReviewStatus(action === "approve"
        ? `Review freigegeben. ${result.correctedFields.length} Feld(er) korrigiert. Eval-Sample: ${result.evalSampleSaved ? "gespeichert" : "ohne OCR-Payload"}.`
        : "Ergebnis wurde abgelehnt und bleibt von Promotion ausgeschlossen.");
      setReviewEditingId("");
      setReviewDraft(null);
      await refresh();
    } catch (reviewError) {
      setReviewStatus(errorMessage(reviewError));
    } finally {
      setReviewPending(false);
    }
  }, [refresh, repositories, reviewDraft, selectedRow]);

  useEffect(() => {
    let canceled = false;
    setSelectedPreview(null);
    const automation = repositories?.automation;
    if (!automation) {
      setPreviewStatus("Electron bridge nicht verfuegbar.");
      return () => {
        canceled = true;
      };
    }
    if (!selectedRow?.runDir || !selectedRow.imagePath || selectedRow.source !== "native") {
      setPreviewStatus(selectedRow?.imagePath ? "Preview nur fuer native Run-Crops verfuegbar." : "");
      return () => {
        canceled = true;
      };
    }

    setPreviewStatus("Preview wird geladen...");
    void automation.nativeScannerLoadImage({
      runDir: selectedRow.runDir,
      imagePath: selectedRow.imagePath,
    }).then((result) => {
      if (canceled) return;
      if (result?.ok) {
        setSelectedPreview({
          dataUrl: result.dataUrl,
          width: result.width,
          height: result.height,
          path: result.path,
        });
        setPreviewStatus(`${result.width}x${result.height}`);
      } else {
        setPreviewStatus(result?.error ?? "Preview konnte nicht geladen werden.");
      }
    }).catch((error: unknown) => {
      if (!canceled) setPreviewStatus(errorMessage(error));
    });

    return () => {
      canceled = true;
    };
  }, [repositories, selectedRow?.id, selectedRow?.imagePath, selectedRow?.runDir, selectedRow?.source]);

  const reviewCount = allRows.filter((row) => row.needsReview).length;
  const nativeCount = allRows.filter((row) => row.source === "native").length;
  const storedCount = allRows.filter((row) => row.source === "store").length;
  const catalogSummary = useMemo(
    () => buildInventoryCatalogSummary(nativeDataStatus, nativeCatalog),
    [nativeCatalog, nativeDataStatus],
  );
  const promotionSummary = useMemo(
    () => buildScanResultPromotionSummary(nativeResults, storedArtifacts),
    [nativeResults, storedArtifacts],
  );
  const pipelineSummary = useMemo(
    () => buildArtifactPipelineSummary(nativeDataStatus, nativeResults, promotionSummary),
    [nativeDataStatus, nativeResults, promotionSummary],
  );
  const statusText = loading
    ? "Inventory wird geladen..."
    : error || `${rows.length}/${allRows.length} Eintraege sichtbar`;

  return {
    rows,
    selectedRow,
    selectedPreview,
    previewStatus,
    filter,
    sort,
    loading,
    statusText,
    promotionStatus,
    promotionPending,
    promotionConfirming,
    reviewEditing,
    reviewPending,
    reviewStatus,
    reviewDraft,
    totalRows: allRows.length,
    nativeCount,
    storedCount,
    reviewCount,
    catalogSummary,
    promotionSummary,
    pipelineSummary,
    filterOptions: [
      { id: "all", label: "Alle", count: allRows.length },
      { id: "native", label: "Native", count: nativeCount },
      { id: "parsed", label: "Gelesen", count: allRows.length - reviewCount },
      { id: "review", label: "Review", count: reviewCount },
      { id: "promotable", label: "Speicherbar", count: promotionSummary.ready },
      { id: "stored", label: "Store", count: storedCount },
    ],
    sortOptions: [
      { id: "newest", label: "Neueste" },
      { id: "name", label: "Name" },
      { id: "status", label: "Status" },
    ],
    setFilter,
    setSort,
    setSelectedId,
    refresh,
    requestSelectedPromotion,
    cancelSelectedPromotion,
    confirmSelectedPromotion,
    startSelectedReview,
    cancelSelectedReview,
    setReviewDraft,
    submitSelectedReview,
  };
}

function errorMessage(value: unknown) {
  return value instanceof Error ? value.message : String(value);
}
