"use client";

import { useState, useEffect } from "react";
import type { FormEvent, MouseEvent } from "react";
import { BlueprintTarget } from "@capakraken/shared";
import type { BlueprintFieldDefinition } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js";
import { BlueprintFieldCatalog } from "./BlueprintFieldCatalog.js";
import { useSelection } from "~/hooks/useSelection.js";
import { BatchActionBar } from "~/components/ui/BatchActionBar.js";
import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js";
import { FilterBar } from "~/components/ui/FilterBar.js";
import { SortableColumnHeader } from "~/components/ui/SortableColumnHeader.js";
import { useTableSort } from "~/hooks/useTableSort.js";
import { useViewPrefs } from "~/hooks/useViewPrefs.js";

const INPUT_CLS =
  "px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 text-sm";

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 text-gray-700 rounded-lg hover:bg-gray-50 text-sm font-medium";

interface NewBlueprintModalProps {
  onClose: () => void;
  onCreated: () => void;
}

type BlueprintTargetValue = "RESOURCE" | "PROJECT";
type BlueprintSortField = "name" | "target" | "fieldCount" | "presetCount" | "global";

function NewBlueprintModal({ onClose, onCreated }: NewBlueprintModalProps) {
  const utils = trpc.useUtils();

  const [name, setName] = useState("");
  const [description, setDescription] = useState("");
  const [target, setTarget] = useState<BlueprintTargetValue>("RESOURCE");
  const [error, setError] = useState<string | null>(null);

  const createMutation = trpc.blueprint.create.useMutation();

  async function handleSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setError(null);
    if (!name.trim()) {
      setError("Name is required.");
      return;
    }

    try {
      await createMutation.mutateAsync({
        name: name.trim(),
        description: description.trim() || undefined,
        target: target as BlueprintTarget,
        fieldDefs: [],
        defaults: {},
        validationRules: [],
      });
      await utils.blueprint.list.invalidate();
      onCreated();
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to create blueprint.");
    }
  }

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

  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 rounded-xl shadow-2xl w-full max-w-md mx-4">
        <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200">
          <h2 className="text-lg font-semibold text-gray-900">New Blueprint</h2>
          <button type="button" onClick={onClose} className="text-gray-400 hover:text-gray-600 text-2xl leading-none" aria-label="Close">×</button>
        </div>
        <form onSubmit={handleSubmit} className="px-6 py-5 space-y-4">
          <div className="flex flex-col gap-1">
            <label className="text-sm font-medium text-gray-700">Name <span className="text-red-500">*</span></label>
            <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Resource Extended Fields" className={INPUT_CLS} autoFocus />
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-sm font-medium text-gray-700">Description</label>
            <textarea value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Optional description" className={`${INPUT_CLS} resize-none`} rows={2} />
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-sm font-medium text-gray-700">Target</label>
            <select value={target} onChange={(e) => setTarget(e.target.value as BlueprintTargetValue)} className={INPUT_CLS}>
              <option value="RESOURCE">Resource</option>
              <option value="PROJECT">Project</option>
            </select>
          </div>
          {error && <p className="text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg px-3 py-2">{error}</p>}
          <div className="flex items-center justify-end gap-3 pt-2">
            <button type="button" onClick={onClose} className={BTN_SECONDARY}>Cancel</button>
            <button type="submit" disabled={createMutation.isPending} className={BTN_PRIMARY}>
              {createMutation.isPending ? "Creating…" : "Create Blueprint"}
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

interface BlueprintRow {
  id: string;
  name: string;
  description: string | null;
  target: BlueprintTargetValue;
  fieldDefs: unknown;
  rolePresets: unknown;
  isGlobal?: boolean;
}

interface BlueprintCardProps {
  blueprint: BlueprintRow;
  onEditFields: () => void;
  onEditStaffing: () => void;
  onToggleGlobal: () => void;
  onDelete: () => void;
  isSelected: boolean;
  onToggleSelect: () => void;
}

function BlueprintCard({
  blueprint,
  onEditFields,
  onEditStaffing,
  onToggleGlobal,
  onDelete,
  isSelected,
  onToggleSelect,
}: BlueprintCardProps) {
  const fieldDefs = Array.isArray(blueprint.fieldDefs) ? (blueprint.fieldDefs as BlueprintFieldDefinition[]) : [];
  const rolePresets = Array.isArray(blueprint.rolePresets) ? (blueprint.rolePresets as unknown[]) : [];
  const fieldCount = fieldDefs.length;
  const presetCount = rolePresets.length;
  const isProject = blueprint.target === "PROJECT";

  return (
    <div className={`bg-white rounded-xl border p-5 flex flex-col gap-3 hover:shadow-sm transition-shadow ${isSelected ? "border-brand-400 bg-brand-50" : "border-gray-200"}`}>
      <div className="flex items-start justify-between gap-3">
        <div className="flex items-start gap-3 flex-1 min-w-0">
          <input
            type="checkbox"
            checked={isSelected}
            onChange={onToggleSelect}
            className="mt-0.5 rounded border-gray-300"
          />
          <div className="flex-1 min-w-0">
            <h3 className="font-semibold text-gray-900 truncate">{blueprint.name}</h3>
            {blueprint.description && (
              <p className="text-xs text-gray-500 mt-0.5 line-clamp-2">{blueprint.description}</p>
            )}
          </div>
        </div>
        <span className={`shrink-0 inline-block px-2 py-0.5 text-xs rounded-full font-medium ${isProject ? "bg-purple-50 text-purple-700" : "bg-blue-50 text-blue-700"}`}>
          {blueprint.target}
        </span>
      </div>

      <div className="flex flex-wrap gap-3 text-sm text-gray-500">
        <span>{fieldCount === 0 ? "No fields" : `${fieldCount} field${fieldCount === 1 ? "" : "s"}`}</span>
        {isProject && (
          <span className={presetCount > 0 ? "text-brand-600 font-medium" : ""}>
            {presetCount === 0 ? "No staffing presets" : `${presetCount} staffing preset${presetCount === 1 ? "" : "s"}`}
          </span>
        )}
        {blueprint.isGlobal && (
          <span className="inline-block px-2 py-0.5 text-xs rounded-full bg-amber-100 text-amber-700 font-medium">Global</span>
        )}
      </div>

      <div className="flex flex-wrap items-center gap-2 pt-1 border-t border-gray-100">
        <button type="button" onClick={onEditFields} className="px-3 py-1.5 bg-brand-600 text-white rounded-lg hover:bg-brand-700 text-sm font-medium transition-colors">
          Edit Fields
        </button>
        {isProject && (
          <button type="button" onClick={onEditStaffing} className="px-3 py-1.5 border border-brand-300 text-brand-700 rounded-lg hover:bg-brand-50 text-sm font-medium transition-colors">
            Edit Staffing Presets
          </button>
        )}
        <button
          type="button"
          onClick={onToggleGlobal}
          className={`px-3 py-1.5 rounded-lg text-sm font-medium transition-colors disabled:opacity-50 ${
            blueprint.isGlobal
              ? "border border-amber-300 text-amber-700 hover:bg-amber-50"
              : "border border-gray-200 text-gray-500 hover:bg-gray-50"
          }`}
          title={blueprint.isGlobal ? "Remove from global columns" : "Make fields available as global columns"}
        >
          {blueprint.isGlobal ? "Unglobalize" : "Make Global"}
        </button>
        <button
          type="button"
          onClick={() => {
            if (window.confirm(`Delete blueprint "${blueprint.name}"?`)) {
              onDelete();
            }
          }}
          className="px-3 py-1.5 border border-red-200 text-red-600 rounded-lg hover:bg-red-50 text-sm font-medium transition-colors disabled:opacity-50"
        >
          Delete
        </button>
      </div>
    </div>
  );
}

export function BlueprintsClient() {
  const [showNewModal, setShowNewModal] = useState(false);
  const [editingBlueprint, setEditingBlueprint] = useState<BlueprintRow | null>(null);
  const [editingTab, setEditingTab] = useState<"fields" | "presets">("fields");
  const [targetFilter, setTargetFilter] = useState<string>("");
  const [confirmBatchDelete, setConfirmBatchDelete] = useState<string[] | null>(null);

  const selection = useSelection();
  const utils = trpc.useUtils();

  const { data, isLoading, isError } = trpc.blueprint.list.useQuery({
    target: (targetFilter as BlueprintTarget) || undefined,
  });

  const batchDeleteMutation = trpc.blueprint.batchDelete.useMutation();
  const deleteMutation = trpc.blueprint.delete.useMutation();
  const setGlobalMutation = trpc.blueprint.setGlobal.useMutation();

  const viewPrefs = useViewPrefs("blueprints");

  useEffect(() => {
    selection.clear();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [targetFilter]);

  const blueprints: BlueprintRow[] = data ?? [];
  const { sorted: sortedBlueprints, sortField, sortDir, toggle } = useTableSort<BlueprintRow, BlueprintSortField>(blueprints, {
    initialField: (viewPrefs.savedSort?.field as BlueprintSortField | undefined) ?? null,
    initialDir: viewPrefs.savedSort?.dir ?? null,
    onSortChange: (field, dir) => {
      viewPrefs.setSavedSort(field && dir ? { field, dir } : null);
    },
  });
  const blueprintIds = sortedBlueprints.map((b) => b.id);

  function handleSort(field: BlueprintSortField) {
    switch (field) {
      case "fieldCount":
        toggle(field, (row) => (Array.isArray(row.fieldDefs) ? row.fieldDefs.length : 0));
        return;
      case "presetCount":
        toggle(field, (row) => (Array.isArray(row.rolePresets) ? row.rolePresets.length : 0));
        return;
      case "global":
        toggle(field, (row) => (row.isGlobal ? 0 : 1));
        return;
      default:
        toggle(field);
    }
  }

  function handleSortRequest(field: string) {
    handleSort(field as BlueprintSortField);
  }

  async function handleDelete(id: string) {
    await deleteMutation.mutateAsync({ id });
    await utils.blueprint.list.invalidate();
    if (selection.selectedIds.has(id)) {
      selection.toggle(id);
    }
    if (editingBlueprint?.id === id) {
      setEditingBlueprint(null);
    }
  }

  async function handleToggleGlobal(id: string, isGlobal: boolean | undefined) {
    await setGlobalMutation.mutateAsync({ id, isGlobal: !isGlobal });
    await utils.blueprint.list.invalidate();
  }

  async function handleBatchDelete(ids: string[]) {
    await batchDeleteMutation.mutateAsync({ ids });
    await utils.blueprint.list.invalidate();
    selection.clear();
  }

  return (
    <div className="p-6 pb-24">
      <div className="flex items-start justify-between mb-6 gap-4">
        <div>
          <h1 className="text-2xl font-bold text-gray-900">Blueprints</h1>
          <p className="text-gray-500 text-sm mt-1">Configure dynamic fields for resources and projects</p>
        </div>
        <button type="button" onClick={() => setShowNewModal(true)} className={BTN_PRIMARY}>
          + New Blueprint
        </button>
      </div>

      <FilterBar
        hasActiveFilters={!!targetFilter}
        onClearFilters={() => setTargetFilter("")}
      >
        <select
          value={targetFilter}
          onChange={(e) => setTargetFilter(e.target.value)}
          className="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 text-sm bg-white"
        >
          <option value="">All Targets</option>
          <option value="RESOURCE">Resource</option>
          <option value="PROJECT">Project</option>
        </select>
      </FilterBar>

      {isLoading && (
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          {[1, 2, 3].map((i) => (
            <div key={i} className="bg-white rounded-xl border border-gray-200 p-5 shimmer-skeleton h-36" />
          ))}
        </div>
      )}

      {isError && (
        <div className="bg-red-50 border border-red-200 rounded-xl p-6 text-red-700 text-sm">
          Failed to load blueprints. Please refresh the page.
        </div>
      )}

      {!isLoading && !isError && blueprints.length === 0 && (
        <div className="flex flex-col items-center justify-center py-20 text-center">
          <p className="text-gray-400 text-sm mb-4">No blueprints yet. Create one to start defining dynamic fields.</p>
          <button type="button" onClick={() => setShowNewModal(true)} className={BTN_PRIMARY}>
            + New Blueprint
          </button>
        </div>
      )}

      {!isLoading && !isError && sortedBlueprints.length > 0 && (
        <>
          <div className="hidden md:block bg-white rounded-xl border border-gray-200 overflow-hidden">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b border-gray-200 bg-gray-50">
                  <th className="w-12 px-3 py-3">
                    <input
                      type="checkbox"
                      checked={selection.isAllSelected(blueprintIds)}
                      onChange={() => selection.toggleAll(blueprintIds)}
                      className="rounded border-gray-300"
                      aria-label="Select all blueprints"
                    />
                  </th>
                  <SortableColumnHeader label="Name" field="name" sortField={sortField} sortDir={sortDir} onSort={handleSortRequest} tooltip="Blueprint name. Defines a template of dynamic fields for resources or projects." />
                  <SortableColumnHeader label="Target" field="target" sortField={sortField} sortDir={sortDir} onSort={handleSortRequest} tooltip="Whether this blueprint applies to Resource or Project entities." />
                  <SortableColumnHeader label="Fields" field="fieldCount" sortField={sortField} sortDir={sortDir} onSort={handleSortRequest} align="center" tooltip="Number of custom dynamic fields defined in this blueprint." />
                  <SortableColumnHeader label="Staffing Presets" field="presetCount" sortField={sortField} sortDir={sortDir} onSort={handleSortRequest} align="center" tooltip="Role presets for project staffing demands. Only applicable to PROJECT blueprints." />
                  <SortableColumnHeader label="Global" field="global" sortField={sortField} sortDir={sortDir} onSort={handleSortRequest} align="center" tooltip="Global blueprints expose their fields as columns across all entities of the target type." />
                  <th className="px-3 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
                </tr>
              </thead>
              <tbody>
                {sortedBlueprints.map((bp) => {
                  const fieldCount = Array.isArray(bp.fieldDefs) ? bp.fieldDefs.length : 0;
                  const presetCount = Array.isArray(bp.rolePresets) ? bp.rolePresets.length : 0;
                  const isProject = bp.target === "PROJECT";

                  return (
                    <tr key={bp.id} className="border-b border-gray-100 dark:border-gray-700/50 last:border-b-0 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">
                      <td className="px-3 py-3">
                        <input
                          type="checkbox"
                          checked={selection.selectedIds.has(bp.id)}
                          onChange={() => selection.toggle(bp.id)}
                          className="rounded border-gray-300"
                        />
                      </td>
                      <td className="px-3 py-3">
                        <div className="min-w-0">
                          <div className="font-medium text-gray-900 dark:text-gray-100">{bp.name}</div>
                          {bp.description && <div className="text-xs text-gray-500 mt-0.5 truncate">{bp.description}</div>}
                        </div>
                      </td>
                      <td className="px-3 py-3">
                        <span className={`inline-block px-2 py-0.5 text-xs rounded-full font-medium ${isProject ? "bg-purple-50 text-purple-700 dark:bg-purple-900/40 dark:text-purple-300" : "bg-blue-50 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300"}`}>
                          {bp.target}
                        </span>
                      </td>
                      <td className="px-3 py-3 text-center text-gray-600 dark:text-gray-400">{fieldCount}</td>
                      <td className="px-3 py-3 text-center text-gray-600 dark:text-gray-400">{isProject ? presetCount : "—"}</td>
                      <td className="px-3 py-3 text-center">
                        {bp.isGlobal ? (
                          <span className="inline-block px-2 py-0.5 text-xs rounded-full bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300 font-medium">
                            Global
                          </span>
                        ) : (
                          <span className="text-gray-300">—</span>
                        )}
                      </td>
                      <td className="px-3 py-3">
                        <div className="flex items-center justify-end gap-2">
                          <button
                            type="button"
                            onClick={() => { setEditingTab("fields"); setEditingBlueprint(bp); }}
                            className="text-xs text-brand-600 hover:text-brand-800 font-medium"
                          >
                            Edit Fields
                          </button>
                          {isProject && (
                            <button
                              type="button"
                              onClick={() => { setEditingTab("presets"); setEditingBlueprint(bp); }}
                              className="text-xs text-brand-600 hover:text-brand-800 font-medium"
                            >
                              Presets
                            </button>
                          )}
                          <button
                            type="button"
                            onClick={() => handleToggleGlobal(bp.id, bp.isGlobal)}
                            disabled={setGlobalMutation.isPending}
                            className="text-xs text-gray-500 hover:text-gray-700 disabled:opacity-50"
                          >
                            {bp.isGlobal ? "Unglobalize" : "Make Global"}
                          </button>
                          <button
                            type="button"
                            onClick={() => {
                              if (window.confirm(`Delete blueprint "${bp.name}"?`)) {
                                handleDelete(bp.id);
                              }
                            }}
                            disabled={deleteMutation.isPending}
                            className="text-xs text-red-500 hover:text-red-700 disabled:opacity-50"
                          >
                            Delete
                          </button>
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>

          <div className="grid grid-cols-1 gap-4 md:hidden">
            {sortedBlueprints.map((bp) => (
              <BlueprintCard
                key={bp.id}
                blueprint={bp}
                onEditFields={() => { setEditingTab("fields"); setEditingBlueprint(bp); }}
                onEditStaffing={() => { setEditingTab("presets"); setEditingBlueprint(bp); }}
                onToggleGlobal={() => handleToggleGlobal(bp.id, bp.isGlobal)}
                onDelete={() => handleDelete(bp.id)}
                isSelected={selection.selectedIds.has(bp.id)}
                onToggleSelect={() => selection.toggle(bp.id)}
              />
            ))}
          </div>
        </>
      )}

      <BatchActionBar
        count={selection.count}
        onClear={selection.clear}
        actions={[
          {
            label: `Delete (${selection.count})`,
            variant: "danger",
            onClick: () => setConfirmBatchDelete(selection.selectedArray),
            disabled: batchDeleteMutation.isPending,
          },
        ]}
      />

      {confirmBatchDelete && (
        <ConfirmDialog
          title="Delete Blueprints"
          message={`Delete ${confirmBatchDelete.length} selected blueprint${confirmBatchDelete.length !== 1 ? "s" : ""}? They will be marked as inactive.`}
          confirmLabel="Delete All"
          variant="danger"
          onConfirm={() => {
            void handleBatchDelete(confirmBatchDelete);
            setConfirmBatchDelete(null);
          }}
          onCancel={() => setConfirmBatchDelete(null)}
        />
      )}

      {showNewModal && (
        <NewBlueprintModal onClose={() => setShowNewModal(false)} onCreated={() => setShowNewModal(false)} />
      )}

      {editingBlueprint && (
        <BlueprintFieldCatalog
          blueprintId={editingBlueprint.id}
          blueprintName={editingBlueprint.name}
          blueprintTarget={editingBlueprint.target}
          initialFieldDefs={Array.isArray(editingBlueprint.fieldDefs) ? (editingBlueprint.fieldDefs as BlueprintFieldDefinition[]) : []}
          initialRolePresets={Array.isArray(editingBlueprint.rolePresets) ? (editingBlueprint.rolePresets as import("@capakraken/shared").StaffingRequirement[]) : []}
          initialTab={editingTab}
          onClose={() => setEditingBlueprint(null)}
        />
      )}
    </div>
  );
}
