"use client";

import { FormEvent, useMemo, useState, useCallback } from "react";
import {
  ColumnMetadata,
  TableMetadata,
  runDdl,
  fetchTableDdl,
  ApiError,
} from "@/app/lib/api";
import { useSettings } from "@/app/lib/settings";
import { toast } from "sonner";
import { cn } from "@/app/lib/utils";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Badge } from "./ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs";
import { ScrollArea } from "./ui/scroll-area";
import { Switch } from "./ui/switch";
import CodeBlock from "./ui/code-block";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "./ui/dialog";
import {
  Columns3,
  Plus,
  Trash2,
  Settings2,
  Loader2,
  Key,
  Hash,
  Type,
  Calendar,
  ToggleLeft,
  AlertCircle,
  CheckCircle2,
  FileCode2,
  X,
  Check,
  Pencil,
  ArrowRight,
  Wrench,
  PanelRightClose,
} from "lucide-react";

type Props = {
  table: TableMetadata | null;
  columns: ColumnMetadata[];
  columnsLoading?: boolean;
  clientName: string | null;
  onSchemaChange: () => void;
  onCollapse?: () => void;
};

const typeIcons: Record<string, React.ComponentType<{ className?: string }>> = {
  uuid: Key,
  integer: Hash,
  bigint: Hash,
  smallint: Hash,
  numeric: Hash,
  "double precision": Hash,
  real: Hash,
  text: Type,
  "character varying": Type,
  varchar: Type,
  boolean: ToggleLeft,
  "timestamp with time zone": Calendar,
  "timestamp without time zone": Calendar,
  date: Calendar,
  timestamptz: Calendar,
  jsonb: Settings2,
  json: Settings2,
};

const COMMON_TYPES = [
  "text",
  "integer",
  "bigint",
  "boolean",
  "uuid",
  "timestamp with time zone",
  "jsonb",
  "numeric",
  "varchar(255)",
  "date",
];

export default function SchemaInspector({
  table,
  columns,
  columnsLoading,
  clientName,
  onSchemaChange,
  onCollapse,
}: Props) {
  const { baseUrl, apiKey } = useSettings();
  const ctx = useMemo(() => ({ baseUrl, apiKey }), [baseUrl, apiKey]);
  const [showAddColumn, setShowAddColumn] = useState(false);
  const [addName, setAddName] = useState("");
  const [addType, setAddType] = useState("text");
  const [addDefault, setAddDefault] = useState("");
  const [dropColumnOpen, setDropColumnOpen] = useState(false);
  const [dropName, setDropName] = useState("");
  const [status, setStatus] = useState<{
    type: "success" | "error";
    message: string;
  } | null>(null);
  const [actionLoading, setActionLoading] = useState(false);
  const [customSql, setCustomSql] = useState("");
  const [ddl, setDdl] = useState<string | null>(null);
  const [ddlLoading, setDdlLoading] = useState(false);

  // Visual alter state
  const [editColOpen, setEditColOpen] = useState(false);
  const [editCol, setEditCol] = useState<ColumnMetadata | null>(null);
  const [editColNewName, setEditColNewName] = useState("");
  const [editColNewType, setEditColNewType] = useState("");
  const [editColNullable, setEditColNullable] = useState(true);
  const [editColDefault, setEditColDefault] = useState("");

  const tableName = table?.table_name ?? "";
  const schemaName = table?.table_schema ?? "public";

  const clearStatus = () => setStatus(null);

  const runStatement = async (statement: string, successMsg: string) => {
    if (!clientName) {
      setStatus({ type: "error", message: "Select a client first" });
      return;
    }
    setActionLoading(true);
    clearStatus();
    try {
      await runDdl(ctx, statement, clientName);
      setStatus({ type: "success", message: successMsg });
      toast.success(successMsg);
      onSchemaChange();
    } catch (err) {
      const msg = err instanceof ApiError ? err.message : "Statement failed";
      setStatus({ type: "error", message: msg });
      toast.error("DDL failed", { description: msg });
    } finally {
      setActionLoading(false);
    }
  };

  const handleAddColumn = async () => {
    if (!addName.trim() || !addType.trim()) {
      setStatus({ type: "error", message: "Column name and type required" });
      return;
    }
    const defaultClause = addDefault.trim()
      ? ` DEFAULT ${addDefault.trim()}`
      : "";
    await runStatement(
      `ALTER TABLE ${schemaName}.${tableName} ADD COLUMN ${addName.trim()} ${addType.trim()}${defaultClause};`,
      `Added column "${addName.trim()}"`,
    );
    setAddName("");
    setAddType("text");
    setAddDefault("");
    setShowAddColumn(false);
  };

  const handleDropColumn = async () => {
    if (!dropName.trim()) return;
    await runStatement(
      `ALTER TABLE ${schemaName}.${tableName} DROP COLUMN ${dropName.trim()};`,
      `Dropped column "${dropName.trim()}"`,
    );
    setDropName("");
    setDropColumnOpen(false);
  };

  const handleCustomSql = async (e: FormEvent) => {
    e.preventDefault();
    if (!customSql.trim()) return;
    await runStatement(customSql.trim(), "Statement executed");
    if (!status || status.type === "success") {
      setCustomSql("");
    }
  };

  const handleLoadDdl = useCallback(async () => {
    if (!tableName) return;
    setDdlLoading(true);
    try {
      if (columns.length > 0) {
        const colDefs = columns.map((c) => {
          let def = `  ${c.column_name} ${c.data_type ?? "text"}`;
          if (c.is_nullable === "NO") def += " NOT NULL";
          if (c.column_default) def += ` DEFAULT ${c.column_default}`;
          return def;
        });
        setDdl(
          `CREATE TABLE ${schemaName}.${tableName} (\n${colDefs.join(",\n")}\n);`,
        );
      } else if (clientName) {
        const result = await fetchTableDdl(
          ctx,
          tableName,
          schemaName,
          clientName,
        );
        setDdl(result);
      } else {
        setDdl("-- No columns available. Connect a client first.");
      }
    } catch {
      setDdl("-- Unable to generate DDL");
    } finally {
      setDdlLoading(false);
    }
  }, [ctx, clientName, tableName, schemaName, columns]);

  const openEditColumn = (col: ColumnMetadata) => {
    setEditCol(col);
    setEditColNewName(col.column_name);
    setEditColNewType(col.data_type ?? "text");
    setEditColNullable(col.is_nullable !== "NO");
    setEditColDefault(col.column_default ?? "");
    setEditColOpen(true);
  };

  const handleEditColumn = async () => {
    if (!editCol || !clientName) return;
    setActionLoading(true);
    clearStatus();

    const statements: string[] = [];

    if (editColNewName !== editCol.column_name) {
      statements.push(
        `ALTER TABLE ${schemaName}.${tableName} RENAME COLUMN ${editCol.column_name} TO ${editColNewName};`,
      );
    }

    if (editColNewType !== (editCol.data_type ?? "text")) {
      statements.push(
        `ALTER TABLE ${schemaName}.${tableName} ALTER COLUMN ${editColNewName} TYPE ${editColNewType} USING ${editColNewName}::${editColNewType};`,
      );
    }

    const wasNullable = editCol.is_nullable !== "NO";
    if (editColNullable !== wasNullable) {
      statements.push(
        editColNullable
          ? `ALTER TABLE ${schemaName}.${tableName} ALTER COLUMN ${editColNewName} DROP NOT NULL;`
          : `ALTER TABLE ${schemaName}.${tableName} ALTER COLUMN ${editColNewName} SET NOT NULL;`,
      );
    }

    const oldDefault = editCol.column_default ?? "";
    if (editColDefault.trim() !== oldDefault.trim()) {
      if (editColDefault.trim()) {
        statements.push(
          `ALTER TABLE ${schemaName}.${tableName} ALTER COLUMN ${editColNewName} SET DEFAULT ${editColDefault.trim()};`,
        );
      } else {
        statements.push(
          `ALTER TABLE ${schemaName}.${tableName} ALTER COLUMN ${editColNewName} DROP DEFAULT;`,
        );
      }
    }

    if (statements.length === 0) {
      setEditColOpen(false);
      setActionLoading(false);
      return;
    }

    try {
      for (const stmt of statements) {
        await runDdl(ctx, stmt, clientName);
      }
      setStatus({
        type: "success",
        message: `Updated column "${editColNewName}"`,
      });
      toast.success(`Column "${editColNewName}" updated`);
      onSchemaChange();
      setEditColOpen(false);
    } catch (err) {
      const msg = err instanceof ApiError ? err.message : "Alter failed";
      setStatus({ type: "error", message: msg });
      toast.error("Alter column failed", { description: msg });
    } finally {
      setActionLoading(false);
    }
  };

  const nullableCount = columns.filter((c) => c.is_nullable === "YES").length;

  if (!table) {
    return (
      <div className="hidden lg:flex w-full flex-col items-center justify-center border-l border-border bg-sidebar p-6 text-muted-foreground">
        <div className="flex h-12 w-12 items-center justify-center rounded bg-muted/50 mb-3">
          <Columns3 className="h-6 w-6 opacity-40" />
        </div>
        <p className="text-xs text-center">
          Select a table to inspect its schema
        </p>
      </div>
    );
  }

  return (
    <div className="hidden lg:flex w-full flex-col border-l border-border bg-sidebar min-w-0">
      {/* Header */}
      <div className="border-b border-border px-4 py-3">
        <div className="flex items-center justify-between gap-2">
          <div className="min-w-0">
            <p className="text-caption uppercase tracking-wider text-muted-foreground">
              Schema
            </p>
            <h3 className="text-sm font-medium text-foreground truncate">
              {tableName}
            </h3>
          </div>
          <div className="flex items-center gap-1.5 shrink-0">
            <Badge variant="default" className="text-caption">
              {columns.length} cols
            </Badge>
            {onCollapse && (
              <button
                onClick={onCollapse}
                className="p-1 rounded text-muted-foreground hover:text-foreground transition-colors"
                title="Hide inspector"
              >
                <PanelRightClose className="h-3.5 w-3.5" />
              </button>
            )}
          </div>
        </div>
      </div>

      {/* Status */}
      {status && (
        <div
          className={cn(
            "flex items-center gap-2 border-b px-4 py-2 text-body-sm",
            status.type === "success"
              ? "border-primary/30 bg-primary/5 text-primary"
              : "border-destructive/30 bg-destructive/5 text-destructive",
          )}
        >
          {status.type === "success" ? (
            <CheckCircle2 className="h-3.5 w-3.5" />
          ) : (
            <AlertCircle className="h-3.5 w-3.5" />
          )}
          <span className="truncate">{status.message}</span>
          <button
            onClick={clearStatus}
            className="ml-auto text-caption opacity-60 hover:opacity-100"
          >
            <X className="h-3 w-3" />
          </button>
        </div>
      )}

      <Tabs defaultValue="columns" className="flex flex-col flex-1 min-h-0">
        <TabsList className="w-full justify-start px-2">
          <TabsTrigger value="columns">
            <Columns3 className="mr-1 h-3 w-3" />
            Columns
          </TabsTrigger>
          <TabsTrigger value="alter">
            <Wrench className="mr-1 h-3 w-3" />
            Alter
          </TabsTrigger>
          <TabsTrigger value="ddl" onClick={handleLoadDdl}>
            <FileCode2 className="mr-1 h-3 w-3" />
            DDL
          </TabsTrigger>
          <TabsTrigger value="actions">
            <Settings2 className="mr-1 h-3 w-3" />
            SQL
          </TabsTrigger>
        </TabsList>

        <TabsContent value="columns" className="flex-1 min-h-0 m-0">
          <div className="flex items-center justify-between border-b border-border px-4 py-2">
            <span className="text-caption text-muted-foreground">
              {nullableCount} nullable
            </span>
            <div className="flex gap-1">
              <Button
                variant="ghost"
                size="sm"
                className="h-6 text-caption"
                onClick={() => {
                  clearStatus();
                  setShowAddColumn(true);
                }}
              >
                <Plus className="h-3 w-3" /> Add
              </Button>
              <Button
                variant="ghost"
                size="sm"
                className="h-6 text-caption text-destructive hover:text-destructive"
                onClick={() => {
                  clearStatus();
                  setDropColumnOpen(true);
                }}
              >
                <Trash2 className="h-3 w-3" /> Drop
              </Button>
            </div>
          </div>

          {showAddColumn && (
            <div className="border-b border-primary/30 bg-primary/5 px-4 py-3 space-y-2 animate-slide-up">
              <div className="flex items-center gap-2">
                <Input
                  value={addName}
                  onChange={(e) => setAddName(e.target.value)}
                  placeholder="column_name"
                  className="h-7 flex-1 text-body-sm"
                  autoFocus
                />
                <select
                  value={addType}
                  onChange={(e) => setAddType(e.target.value)}
                  className="h-7 rounded border border-border bg-background px-2 text-body-sm text-foreground min-w-[100px]"
                >
                  {COMMON_TYPES.map((t) => (
                    <option key={t} value={t}>
                      {t}
                    </option>
                  ))}
                </select>
              </div>
              <div className="flex items-center gap-2">
                <Input
                  value={addDefault}
                  onChange={(e) => setAddDefault(e.target.value)}
                  placeholder="Default (optional)"
                  className="h-7 flex-1 text-body-sm"
                />
                <Button
                  size="sm"
                  className="h-7 text-caption"
                  onClick={handleAddColumn}
                  disabled={actionLoading || !addName.trim()}
                >
                  {actionLoading ? (
                    <Loader2 className="h-3 w-3 animate-spin" />
                  ) : (
                    <Check className="h-3 w-3" />
                  )}
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="h-7 text-caption"
                  onClick={() => {
                    setShowAddColumn(false);
                    setAddName("");
                    setAddType("text");
                    setAddDefault("");
                  }}
                >
                  <X className="h-3 w-3" />
                </Button>
              </div>
            </div>
          )}

          {dropColumnOpen && (
            <div className="border-b border-destructive/30 bg-destructive/5 px-4 py-3 animate-slide-up">
              <div className="flex items-center gap-2">
                <select
                  value={dropName}
                  onChange={(e) => setDropName(e.target.value)}
                  className="h-7 flex-1 rounded border border-border bg-background px-2 text-body-sm text-foreground"
                >
                  <option value="">Select column...</option>
                  {columns.map((c) => (
                    <option key={c.column_name} value={c.column_name}>
                      {c.column_name} ({c.data_type})
                    </option>
                  ))}
                </select>
                <Button
                  variant="destructive"
                  size="sm"
                  className="h-7 text-caption"
                  onClick={handleDropColumn}
                  disabled={actionLoading || !dropName}
                >
                  {actionLoading ? (
                    <Loader2 className="h-3 w-3 animate-spin" />
                  ) : (
                    <Trash2 className="h-3 w-3" />
                  )}
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  className="h-7 text-caption"
                  onClick={() => {
                    setDropColumnOpen(false);
                    setDropName("");
                  }}
                >
                  <X className="h-3 w-3" />
                </Button>
              </div>
            </div>
          )}

          <ScrollArea className="flex-1">
            <div className="divide-y divide-border/50">
              {columnsLoading && columns.length === 0 ? (
                <div className="px-4 py-8 text-center text-body-sm text-muted-foreground">
                  <Loader2 className="h-4 w-4 animate-spin mx-auto mb-2 text-primary" />
                  Loading columns...
                </div>
              ) : columns.length === 0 ? (
                <div className="px-4 py-8 text-center text-body-sm text-muted-foreground">
                  No columns found
                </div>
              ) : (
                columns.map((col) => {
                  const IconComp = typeIcons[col.data_type ?? ""] ?? Type;
                  return (
                    <div
                      key={col.column_name}
                      className="flex items-start gap-2.5 px-4 py-2 hover:bg-accent/30 transition-colors cursor-pointer group"
                      onClick={() => openEditColumn(col)}
                    >
                      <IconComp className="mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
                      <div className="flex-1 min-w-0">
                        <div className="flex items-center gap-1.5">
                          <span className="text-body-sm font-medium text-foreground truncate">
                            {col.column_name}
                          </span>
                          {col.is_nullable === "NO" && (
                            <span className="text-tiny text-warning">
                              required
                            </span>
                          )}
                          <Pencil className="h-2.5 w-2.5 text-muted-foreground/40 opacity-0 group-hover:opacity-100 transition-opacity ml-auto shrink-0" />
                        </div>
                        <div className="flex items-center gap-2 mt-0.5">
                          <span className="text-caption text-muted-foreground">
                            {col.data_type ?? "unknown"}
                          </span>
                          {col.column_default && (
                            <span className="text-tiny text-muted-foreground/60 truncate max-w-[120px]">
                              = {col.column_default}
                            </span>
                          )}
                        </div>
                      </div>
                    </div>
                  );
                })
              )}
            </div>
          </ScrollArea>
        </TabsContent>

        {/* Visual Alter Tab */}
        <TabsContent value="alter" className="flex-1 min-h-0 m-0">
          <ScrollArea className="flex-1">
            <div className="p-4 space-y-3">
              <p className="text-caption text-muted-foreground">
                Click any column to edit its type, name, nullability, or
                default. No SQL required.
              </p>
              {columns.map((col) => {
                const IconComp = typeIcons[col.data_type ?? ""] ?? Type;
                return (
                  <button
                    key={col.column_name}
                    onClick={() => openEditColumn(col)}
                    className="flex items-center gap-3 w-full rounded border border-border bg-card p-3 hover:border-primary/40 hover:bg-primary/5 transition-colors text-left"
                  >
                    <IconComp className="h-4 w-4 text-muted-foreground shrink-0" />
                    <div className="flex-1 min-w-0">
                      <span className="text-body-sm font-medium text-foreground block">
                        {col.column_name}
                      </span>
                      <span className="text-caption text-muted-foreground">
                        {col.data_type ?? "unknown"}
                      </span>
                    </div>
                    <div className="flex items-center gap-1.5 shrink-0">
                      {col.is_nullable === "NO" && (
                        <Badge variant="warning" className="text-2xs px-1">
                          NOT NULL
                        </Badge>
                      )}
                      {col.column_default && (
                        <Badge variant="secondary" className="text-2xs px-1">
                          DEFAULT
                        </Badge>
                      )}
                    </div>
                    <ArrowRight className="h-3 w-3 text-muted-foreground/40 shrink-0" />
                  </button>
                );
              })}
              {columns.length > 0 && (
                <Button
                  variant="outline"
                  size="sm"
                  className="w-full h-8 text-body-sm"
                  onClick={() => {
                    clearStatus();
                    setShowAddColumn(true);
                  }}
                >
                  <Plus className="h-3 w-3" /> Add new column
                </Button>
              )}
            </div>
          </ScrollArea>
        </TabsContent>

        <TabsContent value="ddl" className="flex-1 min-h-0 m-0">
          <ScrollArea className="flex-1">
            <div className="p-4">
              {ddlLoading ? (
                <div className="flex items-center justify-center py-8">
                  <Loader2 className="h-4 w-4 animate-spin text-primary" />
                </div>
              ) : ddl ? (
                <CodeBlock code={ddl} language="sql" showCopy />
              ) : (
                <p className="text-body-sm text-muted-foreground text-center py-4">
                  Click DDL tab to load schema
                </p>
              )}
            </div>
          </ScrollArea>
        </TabsContent>

        <TabsContent value="actions" className="flex-1 min-h-0 m-0">
          <ScrollArea className="flex-1">
            <div className="p-4 space-y-4">
              <div>
                <h4 className="text-caption uppercase tracking-wider text-muted-foreground mb-2">
                  Quick actions
                </h4>
                <div className="grid grid-cols-2 gap-2">
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-7 text-body-sm justify-start"
                    onClick={() => {
                      clearStatus();
                      setShowAddColumn(true);
                    }}
                  >
                    <Plus className="h-3 w-3" /> Add column
                  </Button>
                  <Button
                    variant="outline"
                    size="sm"
                    className="h-7 text-body-sm justify-start text-destructive hover:text-destructive"
                    onClick={() => {
                      clearStatus();
                      setDropColumnOpen(true);
                    }}
                  >
                    <Trash2 className="h-3 w-3" /> Drop column
                  </Button>
                </div>
              </div>

              <div>
                <h4 className="text-caption uppercase tracking-wider text-muted-foreground mb-2">
                  Custom SQL
                </h4>
                <form onSubmit={handleCustomSql} className="space-y-2">
                  <textarea
                    value={customSql}
                    onChange={(e) => setCustomSql(e.target.value)}
                    placeholder={`ALTER TABLE ${tableName} ...`}
                    rows={4}
                    className="w-full rounded border border-input bg-background px-3 py-2 font-mono text-body-sm text-foreground outline-none focus:ring-1 focus:ring-ring resize-y"
                    spellCheck={false}
                  />
                  <Button
                    type="submit"
                    size="sm"
                    className="w-full h-7 text-body-sm"
                    disabled={actionLoading || !customSql.trim()}
                  >
                    {actionLoading && (
                      <Loader2 className="h-3 w-3 animate-spin" />
                    )}
                    Execute
                  </Button>
                </form>
              </div>
            </div>
          </ScrollArea>
        </TabsContent>
      </Tabs>

      {/* Edit Column Dialog */}
      <Dialog open={editColOpen} onOpenChange={setEditColOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>
              Edit column:{" "}
              <span className="font-medium">{editCol?.column_name}</span>
            </DialogTitle>
            <DialogDescription>
              Change the column properties. Rename, change type, toggle
              nullable, or set defaults.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-4 py-2">
            <div className="space-y-1.5">
              <label className="text-xs font-medium text-muted-foreground">
                Column name
              </label>
              <Input
                value={editColNewName}
                onChange={(e) => setEditColNewName(e.target.value)}
                className="h-8 text-xs"
              />
            </div>
            <div className="space-y-1.5">
              <label className="text-xs font-medium text-muted-foreground">
                Data type
              </label>
              <select
                value={editColNewType}
                onChange={(e) => setEditColNewType(e.target.value)}
                className="h-8 w-full rounded border border-border bg-background px-3 text-xs text-foreground outline-none"
              >
                {COMMON_TYPES.map((t) => (
                  <option key={t} value={t}>
                    {t}
                  </option>
                ))}
                {editCol?.data_type &&
                  !COMMON_TYPES.includes(editCol.data_type) && (
                    <option value={editCol.data_type}>
                      {editCol.data_type} (current)
                    </option>
                  )}
              </select>
            </div>
            <Switch
              checked={editColNullable}
              onCheckedChange={setEditColNullable}
              size="sm"
              label="Nullable"
              description={
                editColNullable
                  ? "Column allows NULL values"
                  : "Column requires a value (NOT NULL)"
              }
            />
            <div className="space-y-1.5">
              <label className="text-xs font-medium text-muted-foreground">
                Default value
              </label>
              <Input
                value={editColDefault}
                onChange={(e) => setEditColDefault(e.target.value)}
                placeholder="No default"
                className="h-8 text-xs"
              />
            </div>
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              size="sm"
              onClick={() => setEditColOpen(false)}
            >
              Cancel
            </Button>
            <Button
              size="sm"
              onClick={handleEditColumn}
              disabled={actionLoading}
            >
              {actionLoading && <Loader2 className="h-3 w-3 animate-spin" />}
              Apply changes
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
