"use client";

import { useState, useCallback, useEffect, useMemo } from "react";
import {
  StemeDBClient,
  type ListSourcesResponse,
  type SourceRecordDto,
  type SourceImpactResponse,
  ApiError,
} from "@/lib/api";
import type { PanelState } from "@/lib/types";
import { SOURCE_FETCH_LIMIT } from "@/lib/constants";
import { ErrorState } from "@/components/shared/error-state";
import { SourcesMetrics } from "./sources-metrics";
import { SourcesFilters, type StatusFilter } from "./sources-filters";
import { SourceRow } from "./source-row";
import { SourcesLoadingSkeleton } from "./sources-loading-skeleton";
import { SourcesEmptyState } from "./sources-empty-state";
import { BlockDialog } from "./block-dialog";
import { RestoreDialog } from "./restore-dialog";
import { ImpactDetailPanel } from "./impact-detail-panel";

type DialogState =
  | { type: "none" }
  | { type: "block"; source: SourceRecordDto }
  | { type: "restore"; source: SourceRecordDto }
  | { type: "impact"; source: SourceRecordDto; impact: SourceImpactResponse };

export function SourcesPanel() {
  const [state, setState] = useState<PanelState<ListSourcesResponse>>({
    status: "idle",
  });
  const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
  const [dialogState, setDialogState] = useState<DialogState>({ type: "none" });
  const [impact, setImpact] = useState<SourceImpactResponse | null>(null);
  const [isLoadingImpact, setIsLoadingImpact] = useState(false);
  const [isProcessing, setIsProcessing] = useState(false);

  const fetchData = useCallback(async () => {
    setState({ status: "loading" });
    try {
      const client = new StemeDBClient();
      const data = await client.listSources(SOURCE_FETCH_LIMIT);
      setState({ status: "success", data });
    } catch (err) {
      // 404 means no sources - treat as empty success
      if (err instanceof ApiError && err.status === 404) {
        setState({
          status: "success",
          data: { sources: [], count: 0 },
        });
        return;
      }
      const message =
        err instanceof ApiError
          ? err.userMessage
          : err instanceof Error
            ? err.message
            : "Unknown error";
      setState({ status: "error", error: message });
    }
  }, []);

  // Load data on mount
  useEffect(() => {
    fetchData();
  }, [fetchData]);

  // Fetch impact when block dialog opens
  useEffect(() => {
    if (dialogState.type === "block") {
      setIsLoadingImpact(true);
      setImpact(null);
      const client = new StemeDBClient();
      client
        .getSourceImpact(dialogState.source.hash)
        .then((data) => {
          setImpact(data);
        })
        .catch((err) => {
          console.error("Failed to load impact:", err);
        })
        .finally(() => {
          setIsLoadingImpact(false);
        });
    }
  }, [dialogState]);

  const filteredSources = useMemo(() => {
    if (state.status !== "success") return [];
    if (statusFilter === "all") return state.data.sources;
    return state.data.sources.filter((s) => s.status === statusFilter);
  }, [state, statusFilter]);

  const handleViewImpact = useCallback(async (source: SourceRecordDto) => {
    setIsLoadingImpact(true);
    try {
      const client = new StemeDBClient();
      const impactData = await client.getSourceImpact(source.hash);
      setDialogState({ type: "impact", source, impact: impactData });
    } catch (err) {
      console.error("Failed to load impact:", err);
    } finally {
      setIsLoadingImpact(false);
    }
  }, []);

  const handleBlock = useCallback((source: SourceRecordDto) => {
    setDialogState({ type: "block", source });
  }, []);

  const handleRestore = useCallback((source: SourceRecordDto) => {
    setDialogState({ type: "restore", source });
  }, []);

  const handleBlockNow = useCallback(
    async (reason: string) => {
      if (dialogState.type !== "block") return;

      setIsProcessing(true);
      try {
        const client = new StemeDBClient();
        await client.quarantineSource(dialogState.source.hash, false, reason);
        setDialogState({ type: "none" });
        await fetchData();
      } catch (err) {
        console.error("Failed to block source:", err);
      } finally {
        setIsProcessing(false);
      }
    },
    [dialogState, fetchData]
  );

  const handleReviewFirst = useCallback(() => {
    if (dialogState.type !== "block" || !impact) return;
    setDialogState({
      type: "impact",
      source: dialogState.source,
      impact,
    });
  }, [dialogState, impact]);

  const handleRestoreConfirm = useCallback(
    async (reason: string) => {
      if (dialogState.type !== "restore") return;

      setIsProcessing(true);
      try {
        const client = new StemeDBClient();
        await client.restoreSource(dialogState.source.hash, reason);
        setDialogState({ type: "none" });
        await fetchData();
      } catch (err) {
        console.error("Failed to restore source:", err);
      } finally {
        setIsProcessing(false);
      }
    },
    [dialogState, fetchData]
  );

  const handleCloseDialog = useCallback(() => {
    setDialogState({ type: "none" });
    setImpact(null);
  }, []);

  const handleClearFilter = useCallback(() => {
    setStatusFilter("all");
  }, []);

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="rounded-lg border border-border bg-card p-6">
        <h2 className="text-lg font-medium text-card-foreground mb-2">
          Registered Sources
        </h2>
        <p className="text-sm text-muted-foreground">
          Manage the credibility and status of registered sources. Block
          problematic sources to exclude their assertions from query results.
        </p>
      </div>

      {/* Content */}
      <div className="rounded-lg border border-border bg-card p-6">
        {state.status === "idle" && <SourcesLoadingSkeleton />}
        {state.status === "loading" && <SourcesLoadingSkeleton />}

        {state.status === "error" && (
          <ErrorState
            title="Failed to Load Sources"
            error={state.error}
            onRetry={fetchData}
          />
        )}

        {state.status === "success" && (
          <div className="space-y-6">
            {state.data.sources.length === 0 ? (
              <SourcesEmptyState hasFilter={false} />
            ) : (
              <>
                <SourcesMetrics sources={state.data.sources} />

                <SourcesFilters
                  statusFilter={statusFilter}
                  onStatusFilterChange={setStatusFilter}
                  totalCount={state.data.sources.length}
                  filteredCount={filteredSources.length}
                />

                {filteredSources.length === 0 ? (
                  <SourcesEmptyState
                    hasFilter={statusFilter !== "all"}
                    onClearFilter={handleClearFilter}
                  />
                ) : (
                  <div className="space-y-3">
                    {filteredSources.map((source) => (
                      <SourceRow
                        key={source.hash}
                        source={source}
                        onViewImpact={handleViewImpact}
                        onBlock={handleBlock}
                        onRestore={handleRestore}
                      />
                    ))}
                  </div>
                )}
              </>
            )}
          </div>
        )}
      </div>

      {/* Impact Detail Sheet (slides in from right) */}
      <ImpactDetailPanel
        isOpen={dialogState.type === "impact"}
        impact={dialogState.type === "impact" ? dialogState.impact : null}
        onClose={handleCloseDialog}
      />

      {/* Block Dialog */}
      <BlockDialog
        isOpen={dialogState.type === "block"}
        sourceLabel={
          dialogState.type === "block" ? dialogState.source.label : ""
        }
        impact={impact}
        isLoadingImpact={isLoadingImpact}
        isProcessing={isProcessing}
        onBlockNow={handleBlockNow}
        onReviewFirst={handleReviewFirst}
        onCancel={handleCloseDialog}
      />

      {/* Restore Dialog */}
      <RestoreDialog
        isOpen={dialogState.type === "restore"}
        sourceLabel={
          dialogState.type === "restore" ? dialogState.source.label : ""
        }
        isProcessing={isProcessing}
        onRestore={handleRestoreConfirm}
        onCancel={handleCloseDialog}
      />
    </div>
  );
}
