"use client";

import { useState, useEffect, useRef, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { DatePicker } from "@/components/ui/date-picker";
import { StemeDBClient } from "@/lib/api";

export interface QueryParams {
  subject: string;
  predicate: string;
  includeSourceMetadata: boolean;
  asOf?: number; // Unix timestamp for time-travel queries
}

interface QueryFormProps {
  onSubmit: (params: QueryParams) => void;
  isLoading: boolean;
  initialSubject?: string;
  initialPredicate?: string;
}

export function QueryForm({ onSubmit, isLoading, initialSubject, initialPredicate }: QueryFormProps) {
  const [subject, setSubject] = useState(initialSubject ?? "");
  const [predicate, setPredicate] = useState(initialPredicate ?? "");
  const [includeSourceMetadata, setIncludeSourceMetadata] = useState(true);
  const [asOfDate, setAsOfDate] = useState<Date | undefined>(undefined);

  // Autocomplete state
  const [subjectSuggestions, setSubjectSuggestions] = useState<string[]>([]);
  const [predicateSuggestions, setPredicateSuggestions] = useState<string[]>([]);
  const [showSubjectDropdown, setShowSubjectDropdown] = useState(false);
  const [showPredicateDropdown, setShowPredicateDropdown] = useState(false);
  const [activeSubjectIndex, setActiveSubjectIndex] = useState(-1);
  const [activePredicateIndex, setActivePredicateIndex] = useState(-1);

  const subjectRef = useRef<HTMLDivElement>(null);
  const predicateRef = useRef<HTMLDivElement>(null);
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  // Sync initial values when they change (e.g., from URL params)
  useEffect(() => {
    if (initialSubject !== undefined) setSubject(initialSubject);
  }, [initialSubject]);

  useEffect(() => {
    if (initialPredicate !== undefined) setPredicate(initialPredicate);
  }, [initialPredicate]);

  // Fetch subject suggestions with debounce
  const fetchSubjects = useCallback((query: string) => {
    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(async () => {
      if (!query.trim()) {
        setSubjectSuggestions([]);
        setShowSubjectDropdown(false);
        return;
      }
      try {
        const client = new StemeDBClient();
        const resp = await client.listSubjects(query, 20);
        setSubjectSuggestions(resp.subjects);
        setShowSubjectDropdown(resp.subjects.length > 0);
        setActiveSubjectIndex(-1);
      } catch {
        setSubjectSuggestions([]);
        setShowSubjectDropdown(false);
      }
    }, 200);
  }, []);

  // Fetch predicates when subject is selected
  const fetchPredicates = useCallback(async (subj: string) => {
    if (!subj.trim()) {
      setPredicateSuggestions([]);
      return;
    }
    try {
      const client = new StemeDBClient();
      const resp = await client.listPredicates(subj);
      setPredicateSuggestions(resp.predicates);
    } catch {
      setPredicateSuggestions([]);
    }
  }, []);

  // Close dropdowns on click outside
  useEffect(() => {
    function handleClickOutside(e: MouseEvent) {
      if (subjectRef.current && !subjectRef.current.contains(e.target as Node)) {
        setShowSubjectDropdown(false);
      }
      if (predicateRef.current && !predicateRef.current.contains(e.target as Node)) {
        setShowPredicateDropdown(false);
      }
    }
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  const handleSubjectChange = (value: string) => {
    setSubject(value);
    fetchSubjects(value);
    // Clear predicate suggestions when subject changes
    setPredicateSuggestions([]);
  };

  const selectSubject = (value: string) => {
    setSubject(value);
    setShowSubjectDropdown(false);
    setActiveSubjectIndex(-1);
    fetchPredicates(value);
  };

  const handlePredicateChange = (value: string) => {
    setPredicate(value);
    // Filter existing predicate suggestions locally
    if (predicateSuggestions.length > 0) {
      setShowPredicateDropdown(true);
      setActivePredicateIndex(-1);
    }
  };

  const selectPredicate = (value: string) => {
    setPredicate(value);
    setShowPredicateDropdown(false);
    setActivePredicateIndex(-1);
  };

  const filteredPredicates = predicateSuggestions.filter((p) =>
    p.toLowerCase().includes(predicate.toLowerCase())
  );

  const handleSubjectKeyDown = (e: React.KeyboardEvent) => {
    if (!showSubjectDropdown || subjectSuggestions.length === 0) return;
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setActiveSubjectIndex((i) => Math.min(i + 1, subjectSuggestions.length - 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setActiveSubjectIndex((i) => Math.max(i - 1, 0));
    } else if (e.key === "Enter" && activeSubjectIndex >= 0) {
      e.preventDefault();
      selectSubject(subjectSuggestions[activeSubjectIndex]);
    } else if (e.key === "Escape") {
      setShowSubjectDropdown(false);
    }
  };

  const handlePredicateKeyDown = (e: React.KeyboardEvent) => {
    if (!showPredicateDropdown || filteredPredicates.length === 0) return;
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setActivePredicateIndex((i) => Math.min(i + 1, filteredPredicates.length - 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setActivePredicateIndex((i) => Math.max(i - 1, 0));
    } else if (e.key === "Enter" && activePredicateIndex >= 0) {
      e.preventDefault();
      selectPredicate(filteredPredicates[activePredicateIndex]);
    } else if (e.key === "Escape") {
      setShowPredicateDropdown(false);
    }
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    setShowSubjectDropdown(false);
    setShowPredicateDropdown(false);
    if (subject.trim() && predicate.trim()) {
      onSubmit({
        subject: subject.trim(),
        predicate: predicate.trim(),
        includeSourceMetadata,
        asOf: asOfDate ? Math.floor(asOfDate.getTime() / 1000) : undefined,
      });
    }
  };

  const canSubmit = subject.trim().length > 0 && predicate.trim().length > 0 && !isLoading;

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
        {/* Subject with autocomplete */}
        <div className="space-y-2" ref={subjectRef}>
          <label htmlFor="subject" className="text-sm font-medium text-foreground">
            Subject
          </label>
          <div className="relative">
            <Input
              id="subject"
              placeholder="e.g., semaglutide:gastroparesis_risk"
              value={subject}
              onChange={(e) => handleSubjectChange(e.target.value)}
              onFocus={() => {
                if (subjectSuggestions.length > 0) setShowSubjectDropdown(true);
              }}
              onKeyDown={handleSubjectKeyDown}
              disabled={isLoading}
              autoComplete="off"
            />
            {showSubjectDropdown && subjectSuggestions.length > 0 && (
              <div className="absolute z-50 w-full mt-1 max-h-60 overflow-auto rounded-md border border-border bg-popover shadow-md">
                {subjectSuggestions.map((s, i) => (
                  <button
                    key={s}
                    type="button"
                    className={`w-full px-3 py-2 text-left text-sm font-mono truncate hover:bg-muted ${
                      i === activeSubjectIndex ? "bg-muted" : ""
                    }`}
                    onMouseDown={() => selectSubject(s)}
                  >
                    {s}
                  </button>
                ))}
              </div>
            )}
          </div>
          <p className="text-xs text-muted-foreground">
            The entity you want to query
          </p>
        </div>

        {/* Predicate with autocomplete */}
        <div className="space-y-2" ref={predicateRef}>
          <label htmlFor="predicate" className="text-sm font-medium text-foreground">
            Predicate
          </label>
          <div className="relative">
            <Input
              id="predicate"
              placeholder="e.g., risk_level"
              value={predicate}
              onChange={(e) => handlePredicateChange(e.target.value)}
              onFocus={() => {
                if (filteredPredicates.length > 0) setShowPredicateDropdown(true);
              }}
              onKeyDown={handlePredicateKeyDown}
              disabled={isLoading}
              autoComplete="off"
            />
            {showPredicateDropdown && filteredPredicates.length > 0 && (
              <div className="absolute z-50 w-full mt-1 max-h-60 overflow-auto rounded-md border border-border bg-popover shadow-md">
                {filteredPredicates.map((p, i) => (
                  <button
                    key={p}
                    type="button"
                    className={`w-full px-3 py-2 text-left text-sm font-mono truncate hover:bg-muted ${
                      i === activePredicateIndex ? "bg-muted" : ""
                    }`}
                    onMouseDown={() => selectPredicate(p)}
                  >
                    {p}
                  </button>
                ))}
              </div>
            )}
          </div>
          <p className="text-xs text-muted-foreground">
            The property or relationship to analyze
          </p>
        </div>
      </div>

      {/* Time Travel Date Picker */}
      <div className="space-y-2">
        <label htmlFor="as-of-date" className="text-sm font-medium text-foreground">
          Time Travel (Optional)
        </label>
        <DatePicker
          value={asOfDate}
          onChange={setAsOfDate}
          disabled={isLoading}
          max={new Date()}
          placeholder="Query as of date..."
        />
        <p className="text-xs text-muted-foreground">
          See what the knowledge graph knew at a specific point in time
        </p>
      </div>

      <div className="flex items-center justify-between">
        <label className="flex items-center gap-2 text-sm">
          <input
            type="checkbox"
            checked={includeSourceMetadata}
            onChange={(e) => setIncludeSourceMetadata(e.target.checked)}
            disabled={isLoading}
            className="rounded border-border"
          />
          <span className="text-muted-foreground">Include source metadata</span>
        </label>

        <Button type="submit" disabled={!canSubmit}>
          {isLoading ? (
            <>
              <svg
                className="animate-spin -ml-1 mr-2 h-4 w-4"
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
              >
                <circle
                  className="opacity-25"
                  cx="12"
                  cy="12"
                  r="10"
                  stroke="currentColor"
                  strokeWidth="4"
                />
                <path
                  className="opacity-75"
                  fill="currentColor"
                  d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                />
              </svg>
              Querying...
            </>
          ) : (
            "Query Claims"
          )}
        </Button>
      </div>
    </form>
  );
}
