"use client";

import { useState, useMemo, useCallback } from "react";
import { FieldType } from "@capakraken/shared";
import type { BlueprintFieldDefinition, FieldOption, StaffingRequirement } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js";
import { RolePresetsEditor } from "./RolePresetsEditor.js";
import { FieldCard } from "./FieldCard.js";
import type { FieldOverrides } from "./FieldCard.js";
import {
  getCatalogForTarget,
  getCategoriesForTarget,
  findCatalogField,
} from "~/lib/blueprint-field-catalog.js";
import type { CatalogField } from "~/lib/blueprint-field-catalog.js";

// ---------------------------------------------------------------------------
// Styles
// ---------------------------------------------------------------------------

const INPUT_CLS =
  "px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder:text-gray-400 dark:placeholder:text-gray-500";

const BTN_PRIMARY =
  "px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 text-sm font-medium disabled:opacity-50";

const BTN_SECONDARY =
  "px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 text-sm font-medium";

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

type BlueprintTargetValue = "RESOURCE" | "PROJECT";

/** Internal state for a field: catalog index or custom definition */
interface FieldState {
  /** Catalog key (undefined for custom fields) */
  catalogKey: string | undefined;
  overrides: FieldOverrides;
  /** For custom fields only */
  custom?: {
    key: string;
    label: string;
    type: FieldType;
    options: FieldOption[];
  };
}

// ---------------------------------------------------------------------------
// Helpers: Convert between FieldState and BlueprintFieldDefinition
// ---------------------------------------------------------------------------

function fieldDefToState(
  def: BlueprintFieldDefinition,
  target: BlueprintTargetValue,
): FieldState {
  const catalogField = findCatalogField(target, def.key);
  if (catalogField) {
    return {
      catalogKey: catalogField.key,
      overrides: {
        enabled: true,
        required: def.required,
        showInList: def.showInList ?? false,
        defaultValue: def.defaultValue,
        description: def.description ?? "",
      },
    };
  }
  // Custom field -- not in catalog
  return {
    catalogKey: undefined,
    overrides: {
      enabled: true,
      required: def.required,
      showInList: def.showInList ?? false,
      defaultValue: def.defaultValue,
      description: def.description ?? "",
    },
    custom: {
      key: def.key,
      label: def.label,
      type: def.type,
      options: def.options ?? [],
    },
  };
}

function stateToFieldDef(
  state: FieldState,
  order: number,
  target: BlueprintTargetValue,
): BlueprintFieldDefinition | null {
  if (!state.overrides.enabled) return null;

  if (state.catalogKey) {
    const catalogField = findCatalogField(target, state.catalogKey);
    if (!catalogField) return null;
    const desc = state.overrides.description || catalogField.description;
    return {
      id: catalogField.key,
      key: catalogField.key,
      label: catalogField.label,
      type: catalogField.type,
      required: state.overrides.required,
      order,
      ...(state.overrides.showInList ? { showInList: true } : {}),
      ...(desc ? { description: desc } : {}),
      defaultValue: state.overrides.defaultValue,
      ...(catalogField.options ? { options: catalogField.options } : {}),
    };
  }

  // Custom field
  if (!state.custom) return null;
  const customDesc = state.overrides.description || undefined;
  return {
    id: state.custom.key,
    key: state.custom.key,
    label: state.custom.label,
    type: state.custom.type,
    required: state.overrides.required,
    order,
    ...(state.overrides.showInList ? { showInList: true } : {}),
    ...(customDesc !== undefined ? { description: customDesc } : {}),
    defaultValue: state.overrides.defaultValue,
    ...(state.custom.options.length > 0 ? { options: state.custom.options } : {}),
  };
}

// ---------------------------------------------------------------------------
// Props
// ---------------------------------------------------------------------------

interface BlueprintFieldCatalogProps {
  blueprintId: string;
  blueprintName: string;
  blueprintTarget: BlueprintTargetValue;
  initialFieldDefs: BlueprintFieldDefinition[];
  initialRolePresets?: StaffingRequirement[];
  initialTab?: "fields" | "presets";
  onClose: () => void;
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

const FIELD_TYPES: { value: FieldType; label: string }[] = [
  { value: FieldType.TEXT, label: "Text" },
  { value: FieldType.TEXTAREA, label: "Textarea" },
  { value: FieldType.NUMBER, label: "Number" },
  { value: FieldType.BOOLEAN, label: "Boolean" },
  { value: FieldType.DATE, label: "Date" },
  { value: FieldType.SELECT, label: "Select" },
  { value: FieldType.MULTI_SELECT, label: "Multi-Select" },
  { value: FieldType.URL, label: "URL" },
  { value: FieldType.EMAIL, label: "Email" },
];

export function BlueprintFieldCatalog({
  blueprintId,
  blueprintName,
  blueprintTarget,
  initialFieldDefs,
  initialRolePresets = [],
  initialTab = "fields",
  onClose,
}: BlueprintFieldCatalogProps) {
  const utils = trpc.useUtils();

  const [activeTab, setActiveTab] = useState<"fields" | "presets">(initialTab);
  const [searchQuery, setSearchQuery] = useState("");
  const [activeCategory, setActiveCategory] = useState<string | null>(null);
  const [saveError, setSaveError] = useState<string | null>(null);
  const [presetSaveError, setPresetSaveError] = useState<string | null>(null);

  // -- Custom field form state --
  const [showCustomForm, setShowCustomForm] = useState(false);
  const [customKey, setCustomKey] = useState("");
  const [customLabel, setCustomLabel] = useState("");
  const [customType, setCustomType] = useState<FieldType>(FieldType.TEXT);

  const catalog = useMemo(() => getCatalogForTarget(blueprintTarget), [blueprintTarget]);
  const categories = useMemo(() => getCategoriesForTarget(blueprintTarget), [blueprintTarget]);

  // ---------------------------------------------------------------------------
  // Build initial state from existing fieldDefs + catalog
  // ---------------------------------------------------------------------------

  const [catalogOverrides, setCatalogOverrides] = useState<
    Record<string, FieldOverrides>
  >(() => {
    const map: Record<string, FieldOverrides> = {};
    // Start with all catalog fields disabled
    for (const cf of catalog) {
      map[cf.key] = {
        enabled: false,
        required: false,
        showInList: false,
        defaultValue: cf.defaultValue,
        description: "",
      };
    }
    // Override from existing fieldDefs
    for (const def of initialFieldDefs) {
      const state = fieldDefToState(def, blueprintTarget);
      if (state.catalogKey && map[state.catalogKey]) {
        map[state.catalogKey] = state.overrides;
      }
    }
    return map;
  });

  const [customFields, setCustomFields] = useState<FieldState[]>(() => {
    return initialFieldDefs
      .map((def) => fieldDefToState(def, blueprintTarget))
      .filter((s) => !s.catalogKey);
  });

  // ---------------------------------------------------------------------------
  // Mutations
  // ---------------------------------------------------------------------------

  const updateMutation = trpc.blueprint.update.useMutation();
  const presetMutation = trpc.blueprint.updateRolePresets.useMutation();

  // ---------------------------------------------------------------------------
  // Derived data
  // ---------------------------------------------------------------------------

  const allCategoryNames = useMemo(
    () => [...categories.map((c) => c.name), "Custom Fields"],
    [categories],
  );

  const filteredCatalog = useMemo(() => {
    if (!searchQuery.trim()) return catalog;
    const q = searchQuery.toLowerCase();
    return catalog.filter(
      (f) =>
        f.label.toLowerCase().includes(q) ||
        f.key.toLowerCase().includes(q) ||
        f.description.toLowerCase().includes(q) ||
        f.category.toLowerCase().includes(q),
    );
  }, [catalog, searchQuery]);

  const fieldsByCategory = useMemo(() => {
    const map = new Map<string, CatalogField[]>();
    for (const cat of categories) {
      map.set(cat.name, []);
    }
    for (const f of filteredCatalog) {
      const list = map.get(f.category);
      if (list) list.push(f);
    }
    return map;
  }, [filteredCatalog, categories]);

  const enabledCount = useMemo(() => {
    let count = 0;
    for (const ov of Object.values(catalogOverrides)) {
      if (ov.enabled) count++;
    }
    count += customFields.filter((f) => f.overrides.enabled).length;
    return count;
  }, [catalogOverrides, customFields]);

  // ---------------------------------------------------------------------------
  // Handlers
  // ---------------------------------------------------------------------------

  const handleCatalogFieldChange = useCallback(
    (key: string, overrides: FieldOverrides) => {
      setCatalogOverrides((prev) => ({ ...prev, [key]: overrides }));
    },
    [],
  );

  const handleCustomFieldChange = useCallback(
    (idx: number, overrides: FieldOverrides) => {
      setCustomFields((prev) =>
        prev.map((f, i) => (i === idx ? { ...f, overrides } : f)),
      );
    },
    [],
  );

  function removeCustomField(idx: number) {
    setCustomFields((prev) => prev.filter((_, i) => i !== idx));
  }

  function addCustomField() {
    if (!customKey.trim() || !customLabel.trim()) return;
    // Check for duplicate key
    const allKeys = new Set([
      ...catalog.map((f) => f.key),
      ...customFields.map((f) => f.custom?.key).filter(Boolean),
    ]);
    if (allKeys.has(customKey.trim())) return;

    setCustomFields((prev) => [
      ...prev,
      {
        catalogKey: undefined,
        overrides: {
          enabled: true,
          required: false,
          showInList: false,
          defaultValue: undefined,
          description: "",
        },
        custom: {
          key: customKey.trim(),
          label: customLabel.trim(),
          type: customType,
          options: [],
        },
      },
    ]);
    setCustomKey("");
    setCustomLabel("");
    setCustomType(FieldType.TEXT);
    setShowCustomForm(false);
  }

  function handleSave() {
    setSaveError(null);
    const defs: BlueprintFieldDefinition[] = [];
    let order = 0;

    // Catalog fields first (in catalog order)
    for (const cf of catalog) {
      const ov = catalogOverrides[cf.key];
      if (!ov?.enabled) continue;
      const state: FieldState = { catalogKey: cf.key, overrides: ov };
      const def = stateToFieldDef(state, order, blueprintTarget);
      if (def) {
        defs.push(def);
        order++;
      }
    }

    // Custom fields
    for (const cf of customFields) {
      if (!cf.overrides.enabled) continue;
      const def = stateToFieldDef(cf, order, blueprintTarget);
      if (def) {
        defs.push(def);
        order++;
      }
    }

    updateMutation.mutate(
      { id: blueprintId, data: { fieldDefs: defs } },
      {
        onSuccess: async () => {
          await utils.blueprint.list.invalidate();
          onClose();
        },
        onError: (err) => setSaveError(err.message),
      },
    );
  }

  function handleBackdropClick(e: React.MouseEvent<HTMLDivElement>) {
    if (e.target === e.currentTarget) onClose();
  }

  // ---------------------------------------------------------------------------
  // Collapsed categories
  // ---------------------------------------------------------------------------

  const [collapsedCategories, setCollapsedCategories] = useState<Set<string>>(
    new Set(),
  );

  function toggleCategory(name: string) {
    setCollapsedCategories((prev) => {
      const next = new Set(prev);
      if (next.has(name)) next.delete(name);
      else next.add(name);
      return next;
    });
  }

  // ---------------------------------------------------------------------------
  // Render
  // ---------------------------------------------------------------------------

  return (
    <div
      className="fixed inset-0 bg-black/50 z-50 flex items-start justify-center overflow-y-auto py-8"
      onClick={handleBackdropClick}
    >
      <div className="bg-white dark:bg-gray-900 rounded-xl shadow-2xl w-full max-w-4xl mx-4 flex flex-col max-h-[90vh]">
        {/* Header */}
        <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700 shrink-0">
          <div>
            <h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
              Configure Fields:{" "}
              <span className="text-gray-600 dark:text-gray-400 font-normal">{blueprintName}</span>
            </h2>
            <p className="text-xs text-gray-400 mt-0.5">
              {enabledCount} field{enabledCount !== 1 ? "s" : ""} enabled
            </p>
          </div>
          <button
            type="button"
            onClick={onClose}
            className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 text-2xl leading-none"
            aria-label="Close"
          >
            x
          </button>
        </div>

        {/* Tabs */}
        <div className="flex border-b border-gray-200 dark:border-gray-700 px-6 shrink-0">
          {(["fields", "presets"] as const).map((tab) => (
            <button
              key={tab}
              type="button"
              onClick={() => setActiveTab(tab)}
              className={`px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${
                activeTab === tab
                  ? "border-brand-500 text-brand-600"
                  : "border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
              }`}
            >
              {tab === "fields" ? "Fields" : "Role Presets"}
            </button>
          ))}
        </div>

        {activeTab === "fields" ? (
          <>
            {/* Search + category sidebar layout */}
            <div className="flex flex-1 overflow-hidden">
              {/* Category sidebar */}
              <div className="w-48 shrink-0 border-r border-gray-200 dark:border-gray-700 bg-gray-50/50 dark:bg-gray-900 overflow-y-auto hidden md:block">
                <nav className="py-2">
                  <button
                    type="button"
                    onClick={() => setActiveCategory(null)}
                    className={`w-full text-left px-4 py-2 text-sm transition-colors ${
                      activeCategory === null
                        ? "bg-brand-100 dark:bg-gray-800 text-brand-700 dark:text-brand-400 font-medium border-l-2 border-brand-500"
                        : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800/50 border-l-2 border-transparent"
                    }`}
                  >
                    All Fields
                  </button>
                  {allCategoryNames.map((name) => {
                    const catCount =
                      name === "Custom Fields"
                        ? customFields.length
                        : (fieldsByCategory.get(name)?.length ?? 0);
                    const enabledInCat =
                      name === "Custom Fields"
                        ? customFields.filter((f) => f.overrides.enabled).length
                        : (fieldsByCategory.get(name) ?? []).filter(
                            (f) => catalogOverrides[f.key]?.enabled,
                          ).length;

                    return (
                      <button
                        key={name}
                        type="button"
                        onClick={() => setActiveCategory(name)}
                        className={`w-full text-left px-4 py-2 text-sm transition-colors ${
                          activeCategory === name
                            ? "bg-brand-100 dark:bg-gray-800 text-brand-700 dark:text-brand-400 font-medium border-l-2 border-brand-500"
                            : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800/50 border-l-2 border-transparent"
                        }`}
                      >
                        <span className="truncate block">{name}</span>
                        {catCount > 0 && (
                          <span className="text-xs text-gray-400">
                            {enabledInCat}/{catCount}
                          </span>
                        )}
                      </button>
                    );
                  })}
                </nav>
              </div>

              {/* Main content */}
              <div className="flex-1 flex flex-col overflow-hidden">
                {/* Search bar */}
                <div className="px-4 py-3 border-b border-gray-100 dark:border-gray-700 shrink-0">
                  <input
                    type="text"
                    value={searchQuery}
                    onChange={(e) => setSearchQuery(e.target.value)}
                    placeholder="Search fields..."
                    className={`${INPUT_CLS} w-full`}
                    autoFocus
                  />
                </div>

                {/* Field cards */}
                <div className="flex-1 overflow-y-auto px-4 py-4 space-y-6">
                  {categories
                    .filter(
                      (cat) =>
                        activeCategory === null ||
                        activeCategory === cat.name,
                    )
                    .map((cat) => {
                      const fields = fieldsByCategory.get(cat.name) ?? [];
                      if (fields.length === 0 && searchQuery.trim()) return null;
                      if (fields.length === 0 && activeCategory !== null && activeCategory !== cat.name) return null;

                      const isCollapsed = collapsedCategories.has(cat.name);

                      return (
                        <div key={cat.name}>
                          <button
                            type="button"
                            onClick={() => toggleCategory(cat.name)}
                            className="flex items-center gap-2 mb-3 w-full text-left group"
                          >
                            <span className="text-xs text-gray-400 transition-transform group-hover:text-gray-600">
                              {isCollapsed ? "\u25B6" : "\u25BC"}
                            </span>
                            <h3 className="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider">
                              {cat.name}
                            </h3>
                            <span className="text-xs text-gray-400">
                              {cat.description}
                            </span>
                          </button>
                          {!isCollapsed && (
                            <div className="grid grid-cols-1 gap-2">
                              {fields.map((field) => (
                                <FieldCard
                                  key={field.key}
                                  field={field}
                                  overrides={catalogOverrides[field.key]!}
                                  onChange={(ov) =>
                                    handleCatalogFieldChange(field.key, ov)
                                  }
                                />
                              ))}
                              {fields.length === 0 && (
                                <p className="text-sm text-gray-400 py-2">
                                  No fields in this category.
                                </p>
                              )}
                            </div>
                          )}
                        </div>
                      );
                    })}

                  {/* Custom Fields section */}
                  {(activeCategory === null ||
                    activeCategory === "Custom Fields") && (
                    <div>
                      <button
                        type="button"
                        onClick={() => toggleCategory("Custom Fields")}
                        className="flex items-center gap-2 mb-3 w-full text-left group"
                      >
                        <span className="text-xs text-gray-400 transition-transform group-hover:text-gray-600">
                          {collapsedCategories.has("Custom Fields")
                            ? "\u25B6"
                            : "\u25BC"}
                        </span>
                        <h3 className="text-sm font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wider">
                          Custom Fields
                        </h3>
                        <span className="text-xs text-gray-400">
                          User-defined fields not in the catalog
                        </span>
                      </button>
                      {!collapsedCategories.has("Custom Fields") && (
                        <div className="space-y-2">
                          {customFields.map((cf, idx) => {
                            if (!cf.custom) return null;
                            // Build a pseudo CatalogField for the FieldCard
                            const pseudoCatalog: CatalogField = {
                              key: cf.custom.key,
                              label: cf.custom.label,
                              type: cf.custom.type,
                              category: "Custom Fields",
                              description:
                                cf.overrides.description || "Custom field",
                              ...(cf.custom.options.length > 0
                                ? { options: cf.custom.options }
                                : {}),
                              builtIn: false,
                            };
                            return (
                              <div key={cf.custom.key} className="relative">
                                <FieldCard
                                  field={pseudoCatalog}
                                  overrides={cf.overrides}
                                  onChange={(ov) =>
                                    handleCustomFieldChange(idx, ov)
                                  }
                                />
                                <button
                                  type="button"
                                  onClick={() => removeCustomField(idx)}
                                  className="absolute top-3 right-14 text-xs text-red-400 hover:text-red-600"
                                  title="Remove custom field"
                                >
                                  Remove
                                </button>
                              </div>
                            );
                          })}

                          {/* Add custom field */}
                          {showCustomForm ? (
                            <div className="border border-dashed border-gray-300 dark:border-gray-600 rounded-lg p-4 space-y-3 bg-gray-50/50 dark:bg-gray-800">
                              <div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
                                <div className="flex flex-col gap-1">
                                  <label className="text-xs font-medium text-gray-600">
                                    Key{" "}
                                    <span className="text-red-500">*</span>
                                  </label>
                                  <input
                                    type="text"
                                    value={customKey}
                                    onChange={(e) =>
                                      setCustomKey(
                                        e.target.value.replace(
                                          /[^a-zA-Z0-9_]/g,
                                          "",
                                        ),
                                      )
                                    }
                                    placeholder="field_key"
                                    className={`${INPUT_CLS} font-mono`}
                                  />
                                </div>
                                <div className="flex flex-col gap-1">
                                  <label className="text-xs font-medium text-gray-600">
                                    Label{" "}
                                    <span className="text-red-500">*</span>
                                  </label>
                                  <input
                                    type="text"
                                    value={customLabel}
                                    onChange={(e) =>
                                      setCustomLabel(e.target.value)
                                    }
                                    placeholder="Display Label"
                                    className={INPUT_CLS}
                                  />
                                </div>
                                <div className="flex flex-col gap-1">
                                  <label className="text-xs font-medium text-gray-600">
                                    Type
                                  </label>
                                  <select
                                    value={customType}
                                    onChange={(e) =>
                                      setCustomType(
                                        e.target.value as FieldType,
                                      )
                                    }
                                    className={INPUT_CLS}
                                  >
                                    {FIELD_TYPES.map((ft) => (
                                      <option key={ft.value} value={ft.value}>
                                        {ft.label}
                                      </option>
                                    ))}
                                  </select>
                                </div>
                              </div>
                              <div className="flex items-center gap-2">
                                <button
                                  type="button"
                                  onClick={addCustomField}
                                  disabled={
                                    !customKey.trim() || !customLabel.trim()
                                  }
                                  className={BTN_PRIMARY}
                                >
                                  Add
                                </button>
                                <button
                                  type="button"
                                  onClick={() => {
                                    setShowCustomForm(false);
                                    setCustomKey("");
                                    setCustomLabel("");
                                    setCustomType(FieldType.TEXT);
                                  }}
                                  className={BTN_SECONDARY}
                                >
                                  Cancel
                                </button>
                              </div>
                            </div>
                          ) : (
                            <button
                              type="button"
                              onClick={() => setShowCustomForm(true)}
                              className="flex items-center gap-1.5 text-sm text-brand-600 hover:text-brand-800 font-medium py-2"
                            >
                              <span className="text-lg leading-none">+</span>{" "}
                              Add Custom Field
                            </button>
                          )}
                        </div>
                      )}
                    </div>
                  )}
                </div>
              </div>
            </div>

            {/* Error */}
            {saveError && (
              <div className="mx-6 mb-2 px-3 py-2 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700 shrink-0">
                {saveError}
              </div>
            )}

            {/* Footer */}
            <div className="flex items-center justify-between gap-3 px-6 py-4 border-t border-gray-200 dark:border-gray-700 shrink-0">
              <span className="text-xs text-gray-400">
                {enabledCount} field{enabledCount !== 1 ? "s" : ""} will be
                saved
              </span>
              <div className="flex items-center gap-3">
                <button type="button" onClick={onClose} className={BTN_SECONDARY}>
                  Cancel
                </button>
                <button
                  type="button"
                  onClick={handleSave}
                  disabled={updateMutation.isPending}
                  className={BTN_PRIMARY}
                >
                  {updateMutation.isPending ? "Saving..." : "Save Fields"}
                </button>
              </div>
            </div>
          </>
        ) : (
          <div className="px-6 py-4 overflow-y-auto">
            <p className="text-xs text-gray-500 mb-4">
              Role presets are auto-loaded in Step 3 of the Project Creation
              Wizard when this blueprint is selected.
            </p>
            <RolePresetsEditor
              initialPresets={initialRolePresets}
              onSave={(presets) =>
                presetMutation.mutate(
                  { id: blueprintId, rolePresets: presets },
                  {
                    onSuccess: async () => {
                      await utils.blueprint.list.invalidate();
                      setPresetSaveError(null);
                      onClose();
                    },
                    onError: (err) => {
                      setPresetSaveError(err.message);
                    },
                  },
                )
              }
              isSaving={presetMutation.isPending}
              saveError={presetSaveError}
            />
            <div className="flex justify-start mt-4 border-t border-gray-200 pt-4">
              <button type="button" onClick={onClose} className={BTN_SECONDARY}>
                Close
              </button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
