import { useState } from "react";
import { graphql, useMutation, ConnectionHandler } from "react-relay";
import { isValidNsid } from "@slices/lexicon";
import { Dialog } from "./Dialog.tsx";
import { FormControl } from "./FormControl.tsx";
import { Textarea } from "./Textarea.tsx";
import { Button } from "./Button.tsx";
import { PublishedLexiconsList } from "./PublishedLexiconsList.tsx";
import type { CreateLexiconDialogMutation } from "../__generated__/CreateLexiconDialogMutation.graphql.ts";
import "../components/LexiconTree.tsx"; // Import for fragment

interface CreateLexiconDialogProps {
  open: boolean;
  onClose: () => void;
  sliceUri: string;
  existingNsids: string[];
}

type SourceType = 'published' | 'new' | null;

export function CreateLexiconDialog({
  open,
  onClose,
  sliceUri,
  existingNsids,
}: CreateLexiconDialogProps) {
  const [step, setStep] = useState<1 | 2>(1);
  const [sourceType, setSourceType] = useState<SourceType>(null);
  const [lexiconJson, setLexiconJson] = useState("");
  const [error, setError] = useState("");
  const [isValidating, setIsValidating] = useState(false);

  const [commitMutation, isMutationInFlight] =
    useMutation<CreateLexiconDialogMutation>(
      graphql`
        mutation CreateLexiconDialogMutation(
          $input: NetworkSlicesLexiconInput!
        ) {
          createNetworkSlicesLexicon(input: $input) {
            id
            uri
            cid
            nsid
            description
            definitions
            createdAt
            updatedAt
            excludedFromSync
            slice
            ...LexiconTree_lexicon
          }
        }
      `
    );

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setError("");
    setIsValidating(true);

    try {
      if (!lexiconJson.trim()) {
        setError("Lexicon JSON is required");
        return;
      }

      let lexiconData;
      try {
        lexiconData = JSON.parse(lexiconJson);
      } catch (parseError) {
        setError(
          `Failed to parse lexicon JSON: ${
            parseError instanceof Error ? parseError.message : String(parseError)
          }`
        );
        return;
      }

      // Basic validation for data integrity
      const defs = lexiconData.defs || lexiconData.definitions;
      const id = lexiconData.id || lexiconData.nsid;

      if (!id) {
        setError("Lexicon must have an 'id' field");
        return;
      }

      if (!defs) {
        setError("Lexicon must have a 'defs' field");
        return;
      }

      // Validate NSID format (needs at least 3 segments like "com.example.collection")
      if (!(await isValidNsid(id))) {
        setError(`Invalid lexicon ID: "${id}". Must be a valid NSID with at least 3 segments (e.g., "com.example.post")`);
        return;
      }

      // Check for duplicate NSID
      if (existingNsids.includes(id)) {
        setError(`A lexicon with NSID "${id}" already exists in this slice. Please use a different NSID.`);
        return;
      }

      const nsid = id;
      const definitionsString = JSON.stringify(defs);

      commitMutation({
        variables: {
          input: {
            nsid,
            description: lexiconData.description || "",
            definitions: definitionsString,
            slice: sliceUri,
            createdAt: new Date().toISOString(),
            excludedFromSync: false,
          },
        },
        onCompleted: () => {
          setLexiconJson("");
          setError("");
          onClose();
        },
        onError: (err) => {
          setError(err.message || "Failed to create lexicon");
        },
        updater: (store) => {
          const newLexicon = store.getRootField("createNetworkSlicesLexicon");
          if (!newLexicon) return;

          // Extract the rkey from the slice URI (e.g., "at://did/collection/rkey" -> "rkey")
          const sliceRkey = sliceUri.split("/").pop();
          if (!sliceRkey) return;

          // Use ConnectionHandler to get the connection
          const root = store.getRoot();
          const connection = ConnectionHandler.getConnection(
            root,
            "SliceOverview_networkSlicesLexicons",
            {
              where: {
                slice: { contains: sliceRkey }
              }
            }
          );

          if (connection) {
            // Create and insert a new edge
            const newEdge = ConnectionHandler.createEdge(
              store,
              connection,
              newLexicon,
              "NetworkSlicesLexiconEdge"
            );
            ConnectionHandler.insertEdgeAfter(connection, newEdge);
          }
        },
      });
    } finally {
      setIsValidating(false);
    }
  };

  const handleClose = () => {
    if (isValidating) {
      return; // Prevent closing while validation is in progress
    }
    setStep(1);
    setSourceType(null);
    setLexiconJson("");
    setError("");
    setIsValidating(false);
    onClose();
  };

  const handleSourceSelect = (type: SourceType) => {
    setSourceType(type);
    setStep(2);
    setError("");
  };

  const handleBack = () => {
    setStep(1);
    setSourceType(null);
    setLexiconJson("");
    setError("");
  };

  return (
    <Dialog
      open={open}
      onClose={handleClose}
      title={step === 1 ? "Add Lexicon Definition" : sourceType === 'published' ? "Select Published Lexicon" : "Create New Lexicon"}
      maxWidth="xl"
    >
      {error && (
        <div className="mb-4 p-3 bg-red-900/20 border border-red-800 text-red-300 rounded text-sm whitespace-pre-wrap">
          {error}
        </div>
      )}

      {step === 1 ? (
        <div className="space-y-4">
          <p className="text-sm text-zinc-400 mb-4">
            Choose how you'd like to add a lexicon:
          </p>

          <div className="space-y-3">
            <button
              type="button"
              onClick={() => handleSourceSelect('published')}
              className="w-full text-left p-4 bg-zinc-900/50 hover:bg-zinc-800/50 border border-zinc-800 hover:border-zinc-700 rounded transition-colors"
            >
              <h3 className="text-sm font-medium text-zinc-200 mb-1">
                Add from Published Lexicons
              </h3>
              <p className="text-xs text-zinc-500">
                Browse and select from community-published AT Protocol lexicons
              </p>
            </button>

            <button
              type="button"
              onClick={() => handleSourceSelect('new')}
              className="w-full text-left p-4 bg-zinc-900/50 hover:bg-zinc-800/50 border border-zinc-800 hover:border-zinc-700 rounded transition-colors"
            >
              <h3 className="text-sm font-medium text-zinc-200 mb-1">
                Create New Lexicon
              </h3>
              <p className="text-xs text-zinc-500">
                Write a custom lexicon definition from scratch
              </p>
            </button>
          </div>

          <div className="flex justify-end gap-3 pt-4">
            <Button
              type="button"
              variant="default"
              onClick={handleClose}
            >
              Cancel
            </Button>
          </div>
        </div>
      ) : sourceType === 'new' ? (
        <form className="space-y-4">
          <FormControl label="Lexicon JSON">
            <Textarea
              value={lexiconJson}
              onChange={(e) => setLexiconJson(e.target.value)}
              rows={16}
              className="font-mono"
              placeholder={`{
  "lexicon": 1,
  "id": "network.slices.example",
  "description": "Example record type",
  "defs": {
    "main": {
      "type": "record",
      "key": "tid",
      "record": {
        "type": "object",
        "required": ["text", "createdAt"],
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 300
          },
          "createdAt": {
            "type": "string",
            "format": "datetime"
          }
        }
      }
    }
  }
}`}
              disabled={isMutationInFlight}
            />
            <p className="mt-1 text-xs text-zinc-500">
              Paste a valid AT Protocol lexicon definition in JSON format
            </p>
          </FormControl>

          <div className="flex justify-between gap-3 pt-4">
            <Button
              type="button"
              variant="default"
              onClick={handleBack}
              disabled={isMutationInFlight}
            >
              Back
            </Button>
            <div className="flex gap-3">
              <Button
                type="button"
                variant="default"
                onClick={handleClose}
                disabled={isMutationInFlight}
              >
                Cancel
              </Button>
              <Button
                type="button"
                variant="primary"
                onClick={(e) => {
                  e.preventDefault();
                  e.stopPropagation();
                  handleSubmit(e);
                }}
                disabled={isMutationInFlight || isValidating}
              >
                {isMutationInFlight ? "Adding..." : "Add Lexicon"}
              </Button>
            </div>
          </div>
        </form>
      ) : (
        <PublishedLexiconsList
          existingNsids={existingNsids}
          onSelect={(lexicons) => {
            // Add all lexicons directly without going to JSON editor
            lexicons.forEach((lexicon) => {
              const lexiconData = lexicon.data as Record<string, unknown>;
              const defs = lexiconData.defs || lexiconData.definitions;
              const nsid = lexicon.nsid;
              const definitionsString = JSON.stringify(defs);

              commitMutation({
                variables: {
                  input: {
                    nsid,
                    description: (lexiconData.description as string) || "",
                    definitions: definitionsString,
                    slice: sliceUri,
                    createdAt: new Date().toISOString(),
                    excludedFromSync: false,
                  },
                },
                onCompleted: () => {
                  // Only close dialog after all mutations complete
                  // (This will be called for each lexicon)
                },
                onError: (err) => {
                  setError(err.message || "Failed to create lexicon");
                },
                updater: (store) => {
                  const newLexicon = store.getRootField("createNetworkSlicesLexicon");
                  if (!newLexicon) return;

                  // Extract the rkey from the slice URI (e.g., "at://did/collection/rkey" -> "rkey")
                  const sliceRkey = sliceUri.split("/").pop();
                  if (!sliceRkey) return;

                  // Use ConnectionHandler to get the connection
                  const root = store.getRoot();
                  const connection = ConnectionHandler.getConnection(
                    root,
                    "SliceOverview_networkSlicesLexicons",
                    {
                      where: {
                        slice: { contains: sliceRkey }
                      }
                    }
                  );

                  if (connection) {
                    // Create and insert a new edge
                    const newEdge = ConnectionHandler.createEdge(
                      store,
                      connection,
                      newLexicon,
                      "NetworkSlicesLexiconEdge"
                    );
                    ConnectionHandler.insertEdgeAfter(connection, newEdge);
                  }
                },
              });
            });

            // Close dialog after submitting all mutations
            handleClose();
          }}
          onBack={handleBack}
          onCancel={handleClose}
        />
      )}
    </Dialog>
  );
}
