import { useState } from "react";
import { graphql, useLazyLoadQuery } from "react-relay";
import { FormControl } from "./FormControl.tsx";
import { Input } from "./Input.tsx";
import { Button } from "./Button.tsx";
import { LexiconDependencyConfirmationDialog } from "./LexiconDependencyConfirmationDialog.tsx";
import { resolveDependencies } from "../utils/lexiconDependencies.ts";
import type { PublishedLexiconsListQuery } from "../__generated__/PublishedLexiconsListQuery.graphql.ts";

interface PublishedLexicon {
  uri: string;
  nsid: string;
  description?: string;
  defs: unknown;
  fullData: unknown;
}

interface LexiconWithData {
  nsid: string;
  data: unknown;
}

interface PublishedLexiconsListProps {
  existingNsids: string[];
  onSelect: (lexicons: LexiconWithData[]) => void;
  onBack: () => void;
  onCancel: () => void;
}

const PUBLISHED_LEXICONS_SLICE_URI = "at://did:plc:dzmqinfp7efnofbqg5npjmth/network.slices.slice/3m3fsrppc3p2h";

export function PublishedLexiconsList({
  existingNsids,
  onSelect,
  onBack,
  onCancel,
}: PublishedLexiconsListProps) {
  const [searchQuery, setSearchQuery] = useState("");
  const [showDepsDialog, setShowDepsDialog] = useState(false);
  const [selectedLexicon, setSelectedLexicon] = useState<LexiconWithData | null>(null);
  const [resolvedDeps, setResolvedDeps] = useState<LexiconWithData[]>([]);

  const data = useLazyLoadQuery<PublishedLexiconsListQuery>(
    graphql`
      query PublishedLexiconsListQuery(
        $sliceUri: String!
        $where: SliceRecordsWhereInput
      ) {
        sliceRecords(sliceUri: $sliceUri, first: 1000, where: $where) {
          edges {
            node {
              uri
              collection
              value
            }
          }
        }
      }
    `,
    {
      sliceUri: PUBLISHED_LEXICONS_SLICE_URI,
      where: {
        collection: { eq: "com.atproto.lexicon.schema" },
      },
    },
    {
      fetchPolicy: "store-and-network",
    }
  );

  // Parse and filter published lexicons
  const publishedLexicons = data.sliceRecords.edges
    .map((edge) => {
      try {
        const lexiconData = JSON.parse(edge.node.value);
        const nsid = lexiconData.id || lexiconData.nsid;
        const defs = lexiconData.defs || lexiconData.definitions;

        if (!nsid || !defs) return null;

        return {
          uri: edge.node.uri,
          nsid,
          description: lexiconData.description,
          defs,
          fullData: lexiconData,
        } as PublishedLexicon;
      } catch {
        return null;
      }
    })
    .filter((lex): lex is PublishedLexicon => lex !== null);

  // Filter by search query
  const filteredLexicons = publishedLexicons.filter((lex) => {
    if (!searchQuery) return true;
    const query = searchQuery.toLowerCase();
    return (
      lex.nsid.toLowerCase().includes(query) ||
      lex.description?.toLowerCase().includes(query)
    );
  });

  // Check if lexicon already exists in slice
  const isAlreadyAdded = (nsid: string) => existingNsids.includes(nsid);

  // Handle lexicon selection with dependency resolution
  const handleLexiconClick = (lexicon: PublishedLexicon) => {
    if (isAlreadyAdded(lexicon.nsid)) return;

    // Convert to LexiconWithData format
    const mainLexicon: LexiconWithData = {
      nsid: lexicon.nsid,
      data: lexicon.fullData,
    };

    // Convert all published lexicons to LexiconWithData format
    const allLexicons: LexiconWithData[] = publishedLexicons.map(lex => ({
      nsid: lex.nsid,
      data: lex.fullData,
    }));

    // Resolve dependencies
    const dependencies = resolveDependencies(mainLexicon, allLexicons, existingNsids);

    // If there are dependencies, show confirmation dialog
    if (dependencies.length > 0) {
      setSelectedLexicon(mainLexicon);
      setResolvedDeps(dependencies);
      setShowDepsDialog(true);
    } else {
      // No dependencies, add directly
      onSelect([mainLexicon]);
    }
  };

  // Handle confirmation dialog confirmation
  const handleConfirmDeps = () => {
    if (selectedLexicon) {
      onSelect([selectedLexicon, ...resolvedDeps]);
    }
    setShowDepsDialog(false);
    setSelectedLexicon(null);
    setResolvedDeps([]);
  };

  // Handle confirmation dialog cancellation
  const handleCancelDeps = () => {
    setShowDepsDialog(false);
    setSelectedLexicon(null);
    setResolvedDeps([]);
  };

  return (
    <div className="space-y-4">
      <FormControl label="Search Lexicons" htmlFor="search">
        <Input
          id="search"
          type="text"
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          placeholder="Filter by NSID or description..."
        />
      </FormControl>

      <div className="h-96 overflow-y-auto">
        {filteredLexicons.length === 0 ? (
          <div className="text-center py-8 text-sm text-zinc-500">
            {searchQuery ? "No lexicons match your search" : "No published lexicons found"}
          </div>
        ) : (
          filteredLexicons.map((lexicon) => {
            const alreadyAdded = isAlreadyAdded(lexicon.nsid);
            const parts = lexicon.nsid.split(".");
            const authority = parts.length >= 2 ? `${parts[0]}.${parts[1]}` : parts[0];
            const rest = parts.length >= 2 ? parts.slice(2).join(".") : "";

            // Check if this is a record type lexicon
            let isRecordType = false;
            try {
              const defs = lexicon.defs as Record<string, { type?: string }> | undefined;
              isRecordType = defs?.main?.type === "record";
            } catch {
              // ignore
            }

            // Split the rest into middle and last part if it's a record type
            let middle = rest;
            let lastPart = "";
            if (isRecordType && rest) {
              const restParts = rest.split(".");
              if (restParts.length > 1) {
                lastPart = restParts[restParts.length - 1];
                middle = restParts.slice(0, -1).join(".");
              } else {
                lastPart = rest;
                middle = "";
              }
            }

            return (
              <button
                key={lexicon.uri}
                type="button"
                onClick={() => handleLexiconClick(lexicon)}
                disabled={alreadyAdded}
                className={`w-full text-left py-1 rounded group transition-colors ${
                  alreadyAdded
                    ? "opacity-50 cursor-not-allowed"
                    : "hover:bg-zinc-900/50 cursor-pointer"
                }`}
              >
                <div className="flex items-center gap-2">
                  <span className="text-sm font-medium font-mono">
                    <span className="text-zinc-200">{authority}</span>
                    {isRecordType ? (
                      <>
                        {middle && <span className="text-zinc-400">.{middle}</span>}
                        {lastPart && (
                          <>
                            <span className="text-zinc-400">.</span>
                            <span className="text-cyan-400">{lastPart}</span>
                          </>
                        )}
                      </>
                    ) : (
                      rest && <span className="text-zinc-400">.{rest}</span>
                    )}
                  </span>
                  {alreadyAdded && (
                    <span className="text-xs text-zinc-600">
                      (added)
                    </span>
                  )}
                  {lexicon.description && (
                    <span className="text-xs text-zinc-600 truncate">
                      {lexicon.description}
                    </span>
                  )}
                </div>
              </button>
            );
          })
        )}
      </div>

      <div className="flex justify-between gap-3 pt-4">
        <Button type="button" variant="default" onClick={onBack}>
          Back
        </Button>
        <Button type="button" variant="default" onClick={onCancel}>
          Cancel
        </Button>
      </div>

      {/* Dependency confirmation dialog */}
      <LexiconDependencyConfirmationDialog
        open={showDepsDialog}
        mainLexiconNsid={selectedLexicon?.nsid || ""}
        dependencies={resolvedDeps.map(dep => dep.nsid)}
        onConfirm={handleConfirmDeps}
        onCancel={handleCancelDeps}
      />
    </div>
  );
}
