"use client";

import { useState, useCallback, Suspense } from "react";
import { useSearchParams } from "next/navigation";
import { useTransactions, useBanks, useUpdateTransaction, useBulkAction, useTags, useStatement, useCreateRule } from "@/lib/hooks";
import { CATEGORIES, formatCategory } from "@/lib/categories";
import { SplitModal } from "@/components/split-modal";
import { TagPicker } from "@/components/tag-picker";

function formatDate(d: string) {
  return new Date(d).toLocaleDateString("en-AU", {
    day: "2-digit",
    month: "short",
    year: "numeric",
  });
}

const SPEND_TYPES = new Set(["debit", "fee", "interest"]);

function formatAmount(amount: number, type: string) {
  const formatted = new Intl.NumberFormat("en-AU", {
    style: "currency",
    currency: "AUD",
  }).format(amount);
  return SPEND_TYPES.has(type) ? formatted : `+${formatted}`;
}

const TYPE_COLORS: Record<string, string> = {
  debit: "bg-red-900/30 text-red-400",
  credit: "bg-green-900/30 text-green-400",
  payment: "bg-blue-900/30 text-blue-400",
  refund: "bg-emerald-900/30 text-emerald-400",
  fee: "bg-yellow-900/30 text-yellow-400",
  interest: "bg-orange-900/30 text-orange-400",
  transfer: "bg-zinc-800 text-zinc-400",
};

const TYPE_OPTIONS = [
  "debit", "credit", "payment", "refund", "fee", "interest", "transfer",
].map((t) => ({ value: t, label: t }));

function TypeBadge({ type }: { type: string }) {
  return (
    <span className={`px-2 py-0.5 rounded text-xs font-medium ${TYPE_COLORS[type] || "bg-zinc-800 text-zinc-400"}`}>
      {type}
    </span>
  );
}

function EditableTypeBadge({ type, onSave }: { type: string; onSave: (t: string) => void }) {
  const [editing, setEditing] = useState(false);
  if (!editing) {
    return (
      <button onClick={() => setEditing(true)} title="Click to change type">
        <TypeBadge type={type} />
      </button>
    );
  }
  return (
    <select
      autoFocus
      defaultValue={type}
      onBlur={(e) => { onSave(e.target.value); setEditing(false); }}
      onChange={(e) => { onSave(e.target.value); setEditing(false); }}
      className="bg-zinc-800 border border-zinc-600 rounded px-1 py-0.5 text-xs"
    >
      {TYPE_OPTIONS.map((o) => (
        <option key={o.value} value={o.value}>{o.label}</option>
      ))}
    </select>
  );
}

// Prompt shown after a merchant/category edit — offers to save it as a rule
function SaveAsRulePrompt({
  tx,
  field,
  newValue,
  onDone,
}: {
  tx: { id: number; effective_merchant: string; description: string; bank_name: string };
  field: "category" | "merchant";
  newValue: string;
  onDone: () => void;
}) {
  const createRule = useCreateRule();
  const [saving, setSaving] = useState(false);

  // Build a sensible default rule from the transaction context.
  // Prefer merchant_normalized (full name, exact match) over a partial description word.
  const hasMerchant = !!tx.effective_merchant;
  const conditionField = hasMerchant ? "merchant_normalized" : "description";
  const conditionOperator = hasMerchant ? "equals" : "contains";
  const conditionValue = hasMerchant ? tx.effective_merchant : tx.description;

  const defaultName =
    field === "category"
      ? `${conditionValue} → ${formatCategory(newValue)}`
      : `Rename ${conditionValue} → ${newValue}`;

  const conditions = [{ field: conditionField, operator: conditionOperator, value: conditionValue }];
  const actions =
    field === "category"
      ? { set_category: newValue }
      : { set_merchant: newValue };

  async function save() {
    setSaving(true);
    await createRule.mutateAsync({ name: defaultName, conditions, actions, enabled: true, priority: 0 });
    onDone();
  }

  return (
    <div className="fixed bottom-4 right-4 z-50 bg-zinc-800 border border-zinc-600 rounded-xl shadow-2xl p-4 w-80 text-sm">
      <p className="text-zinc-200 font-medium mb-1">Save as rule?</p>
      <p className="text-zinc-400 text-xs mb-3">
        Automatically apply this {field === "category" ? "category" : "merchant name"} to future matching transactions.
      </p>
      <div className="bg-zinc-900 rounded-lg px-3 py-2 text-xs text-zinc-300 mb-3 space-y-1">
        <p><span className="text-zinc-500">If</span> {conditionField === "merchant_normalized" ? "merchant" : "description"} {conditionOperator} <span className="text-white">"{conditionValue}"</span></p>
        <p>
          <span className="text-zinc-500">Then</span>{" "}
          {field === "category"
            ? <>set category → <span className="text-white">{formatCategory(newValue)}</span></>
            : <>set merchant → <span className="text-white">{newValue}</span></>}
        </p>
      </div>
      <div className="flex gap-2">
        <button
          onClick={save}
          disabled={saving}
          className="flex-1 bg-blue-600 hover:bg-blue-500 disabled:opacity-50 text-white rounded-lg py-1.5 font-medium transition-colors"
        >
          {saving ? "Saving…" : "Save rule"}
        </button>
        <button
          onClick={onDone}
          className="flex-1 bg-zinc-700 hover:bg-zinc-600 text-zinc-200 rounded-lg py-1.5 transition-colors"
        >
          Dismiss
        </button>
      </div>
    </div>
  );
}

function InlineEdit({
  value,
  onSave,
  type = "text",
  options,
}: {
  value: string;
  onSave: (val: string) => void;
  type?: "text" | "select";
  options?: { value: string; label: string }[];
}) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(value);

  if (!editing) {
    return (
      <button
        onClick={() => { setDraft(value); setEditing(true); }}
        className="text-left hover:bg-zinc-800 px-1 -mx-1 rounded cursor-pointer transition-colors w-full truncate"
        title="Click to edit"
      >
        {value || <span className="text-zinc-600 italic">unset</span>}
      </button>
    );
  }

  const commit = () => {
    if (draft !== value) onSave(draft);
    setEditing(false);
  };

  if (type === "select" && options) {
    return (
      <select
        autoFocus
        value={draft}
        onChange={(e) => { setDraft(e.target.value); }}
        onBlur={commit}
        className="bg-zinc-800 border border-zinc-600 rounded px-1 py-0.5 text-sm w-full"
      >
        {options.map((o) => (
          <option key={o.value} value={o.value}>{o.label}</option>
        ))}
      </select>
    );
  }

  return (
    <input
      autoFocus
      value={draft}
      onChange={(e) => setDraft(e.target.value)}
      onBlur={commit}
      onKeyDown={(e) => { if (e.key === "Enter") commit(); if (e.key === "Escape") setEditing(false); }}
      className="bg-zinc-800 border border-zinc-600 rounded px-1 py-0.5 text-sm w-full"
    />
  );
}

export default function TransactionsPage() {
  return (
    <Suspense fallback={<p className="text-zinc-500 text-sm">Loading...</p>}>
      <TransactionsContent />
    </Suspense>
  );
}

function TransactionsContent() {
  const searchParams = useSearchParams();
  const initialStatementId = searchParams.get("statement_id") || "";

  const [filters, setFilters] = useState({
    from: "",
    to: "",
    category: "",
    bank_name: "",
    search: "",
    statement_id: initialStatementId,
    tag_id: "",
    sort_by: "transaction_date",
    sort_dir: "desc",
    limit: 50,
    offset: 0,
  });
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [bulkCategory, setBulkCategory] = useState("");
  const [bulkTagId, setBulkTagId] = useState("");
  const [splitModal, setSplitModal] = useState<{ transactionId?: number; transactionIds?: number[]; amount?: number; description: string; merchant?: string } | null>(null);
  const [rulePrompt, setRulePrompt] = useState<{
    tx: { id: number; effective_merchant: string; description: string; bank_name: string };
    field: "category" | "merchant";
    newValue: string;
  } | null>(null);

  const { data, isLoading } = useTransactions(filters);
  const { data: banks } = useBanks();
  const { data: tags } = useTags();
  const { data: statementInfo } = useStatement(parseInt(filters.statement_id) || 0);
  const updateTxn = useUpdateTransaction();
  const bulkAction = useBulkAction();

  const toggleSelect = useCallback((id: number) => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }, []);

  const toggleAll = useCallback(() => {
    if (!data?.data) return;
    setSelected((prev) => {
      if (prev.size === data.data.length) return new Set();
      return new Set(data.data.map((t) => t.id));
    });
  }, [data]);

  const setPage = (newOffset: number) => {
    setFilters((f) => ({ ...f, offset: newOffset }));
    setSelected(new Set());
  };

  const toggleSort = (col: string) => {
    setFilters((f) => ({
      ...f,
      sort_by: col,
      sort_dir: f.sort_by === col && f.sort_dir === "desc" ? "asc" : "desc",
      offset: 0,
    }));
  };

  const categoryOptions = CATEGORIES.map((c) => ({ value: c, label: formatCategory(c) }));

  const totalPages = data ? Math.ceil(data.total / filters.limit) : 0;
  const currentPage = Math.floor(filters.offset / filters.limit) + 1;

  return (
    <div>
      <h2 className="text-xl font-semibold mb-4">Transactions</h2>

      {/* Statement context banner */}
      {filters.statement_id && statementInfo && (
        <div className="flex items-center gap-3 mb-4 px-3 py-2 bg-indigo-950/40 border border-indigo-800/50 rounded-lg text-sm">
          <span className="text-indigo-300 font-medium">{statementInfo.bank_name}</span>
          {statementInfo.billing_start_date && statementInfo.billing_end_date && (
            <span className="text-zinc-400">
              {new Date(statementInfo.billing_start_date).toLocaleDateString("en-AU", { day: "2-digit", month: "short" })}
              {" – "}
              {new Date(statementInfo.billing_end_date).toLocaleDateString("en-AU", { day: "2-digit", month: "short", year: "numeric" })}
            </span>
          )}
          <span className="text-zinc-500 text-xs">{statementInfo.transaction_count} transactions</span>
          <button
            onClick={() => setFilters((f) => ({ ...f, statement_id: "", offset: 0 }))}
            className="ml-auto text-zinc-500 hover:text-zinc-200 text-xs px-2 py-0.5 rounded hover:bg-zinc-800 transition-colors"
          >
            × Clear filter
          </button>
        </div>
      )}

      {/* Filter bar */}
      <div className="flex flex-wrap gap-3 mb-4">
        <input
          type="text"
          placeholder="Search..."
          value={filters.search}
          onChange={(e) => setFilters((f) => ({ ...f, search: e.target.value, offset: 0 }))}
          className="bg-zinc-900 border border-zinc-700 rounded px-3 py-1.5 text-sm w-48"
        />
        <input
          type="date"
          value={filters.from}
          onChange={(e) => setFilters((f) => ({ ...f, from: e.target.value, offset: 0 }))}
          className="bg-zinc-900 border border-zinc-700 rounded px-3 py-1.5 text-sm"
        />
        <input
          type="date"
          value={filters.to}
          onChange={(e) => setFilters((f) => ({ ...f, to: e.target.value, offset: 0 }))}
          className="bg-zinc-900 border border-zinc-700 rounded px-3 py-1.5 text-sm"
        />
        <select
          value={filters.category}
          onChange={(e) => setFilters((f) => ({ ...f, category: e.target.value, offset: 0 }))}
          className="bg-zinc-900 border border-zinc-700 rounded px-3 py-1.5 text-sm"
        >
          <option value="">All Categories</option>
          {CATEGORIES.map((c) => (
            <option key={c} value={c}>{formatCategory(c)}</option>
          ))}
        </select>
        <select
          value={filters.bank_name}
          onChange={(e) => setFilters((f) => ({ ...f, bank_name: e.target.value, offset: 0 }))}
          className="bg-zinc-900 border border-zinc-700 rounded px-3 py-1.5 text-sm"
        >
          <option value="">All Banks</option>
          {banks?.map((b) => (
            <option key={b} value={b}>{b}</option>
          ))}
        </select>
        <select
          value={filters.tag_id}
          onChange={(e) => setFilters((f) => ({ ...f, tag_id: e.target.value, offset: 0 }))}
          className="bg-zinc-900 border border-zinc-700 rounded px-3 py-1.5 text-sm"
        >
          <option value="">All Tags</option>
          {tags?.map((t) => (
            <option key={t.id} value={t.id}>{t.name}</option>
          ))}
        </select>
      </div>

      {/* Bulk action bar */}
      {selected.size > 0 && (
        <div className="flex items-center gap-3 mb-3 p-2 bg-zinc-900 border border-zinc-700 rounded">
          <span className="text-sm text-zinc-400">{selected.size} selected</span>
          <select
            value={bulkCategory}
            onChange={(e) => setBulkCategory(e.target.value)}
            className="bg-zinc-800 border border-zinc-600 rounded px-2 py-1 text-sm"
          >
            <option value="">Set category...</option>
            {CATEGORIES.map((c) => (
              <option key={c} value={c}>{formatCategory(c)}</option>
            ))}
          </select>
          <button
            disabled={!bulkCategory || bulkAction.isPending}
            onClick={() => {
              bulkAction.mutate(
                { action: "categorize", ids: Array.from(selected), category: bulkCategory },
                { onSuccess: () => { setSelected(new Set()); setBulkCategory(""); } }
              );
            }}
            className="px-3 py-1 bg-blue-600 hover:bg-blue-700 disabled:opacity-50 rounded text-sm"
          >
            Apply
          </button>
          <button
            onClick={() =>
              setSplitModal({
                transactionIds: Array.from(selected),
                description: `${selected.size} selected transaction${selected.size !== 1 ? "s" : ""}`,
              })
            }
            className="px-3 py-1 bg-zinc-700 hover:bg-zinc-600 rounded text-sm"
          >
            Split...
          </button>
          <select
            value={bulkTagId}
            onChange={(e) => setBulkTagId(e.target.value)}
            className="bg-zinc-800 border border-zinc-600 rounded px-2 py-1 text-sm"
          >
            <option value="">Tag as...</option>
            {tags?.map((t) => (
              <option key={t.id} value={t.id}>{t.name}</option>
            ))}
          </select>
          <button
            disabled={!bulkTagId || bulkAction.isPending}
            onClick={() => {
              bulkAction.mutate(
                { action: "tag", ids: Array.from(selected), tag_id: Number(bulkTagId) },
                { onSuccess: () => { setSelected(new Set()); setBulkTagId(""); } }
              );
            }}
            className="px-3 py-1 bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 rounded text-sm"
          >
            Tag
          </button>
          <button
            onClick={() => setSelected(new Set())}
            className="px-3 py-1 text-zinc-400 hover:text-white text-sm"
          >
            Clear
          </button>
        </div>
      )}

      {/* Table */}
      <div className="overflow-x-auto border border-zinc-800 rounded-lg">
        <table className="w-full text-sm">
          <thead>
            <tr className="border-b border-zinc-800 bg-zinc-900/50">
              <th className="p-2 w-8">
                <input
                  type="checkbox"
                  checked={data?.data.length ? selected.size === data.data.length : false}
                  onChange={toggleAll}
                  className="accent-blue-600"
                />
              </th>
              <th
                className="p-2 text-left cursor-pointer hover:text-white"
                onClick={() => toggleSort("transaction_date")}
              >
                Date {filters.sort_by === "transaction_date" && (filters.sort_dir === "desc" ? "\u2193" : "\u2191")}
              </th>
              <th className="p-2 text-left">Description</th>
              <th className="p-2 text-left">Merchant</th>
              <th
                className="p-2 text-right cursor-pointer hover:text-white"
                onClick={() => toggleSort("amount")}
              >
                Amount {filters.sort_by === "amount" && (filters.sort_dir === "desc" ? "\u2193" : "\u2191")}
              </th>
              <th className="p-2 text-left">Type</th>
              <th className="p-2 text-left">Category</th>
              <th className="p-2 text-left">Bank</th>
              <th className="p-2 text-left">Tags</th>
              <th className="p-2"></th>
            </tr>
          </thead>
          <tbody>
            {isLoading ? (
              <tr><td colSpan={10} className="p-8 text-center text-zinc-500">Loading...</td></tr>
            ) : !data?.data.length ? (
              <tr><td colSpan={10} className="p-8 text-center text-zinc-500">No transactions found</td></tr>
            ) : (
              data.data.map((t) => (
                <tr
                  key={t.id}
                  className={`border-b border-zinc-800/50 hover:bg-zinc-900/30 ${
                    selected.has(t.id) ? "bg-zinc-800/40" : ""
                  }`}
                >
                  <td className="p-2">
                    <input
                      type="checkbox"
                      checked={selected.has(t.id)}
                      onChange={() => toggleSelect(t.id)}
                      className="accent-blue-600"
                    />
                  </td>
                  <td className="p-2 whitespace-nowrap">{formatDate(t.transaction_date)}</td>
                  <td className="p-2 max-w-xs truncate" title={t.description}>{t.description}</td>
                  <td className="p-2 max-w-[150px]">
                    <div className="relative">
                      <InlineEdit
                        value={t.effective_merchant || ""}
                        onSave={(val) => {
                          updateTxn.mutate({ id: t.id, merchant_normalized: val });
                          setRulePrompt({ tx: t, field: "merchant", newValue: val });
                        }}
                      />
                      {t.merchant_override && (
                        <span className="absolute -left-2 top-1/2 -translate-y-1/2 w-1.5 h-1.5 bg-blue-500 rounded-full" title="Manually overridden" />
                      )}
                    </div>
                  </td>
                  <td className={`p-2 text-right whitespace-nowrap font-mono ${
                    SPEND_TYPES.has(t.transaction_type) ? "text-red-400" : "text-green-400"
                  }`}>
                    {formatAmount(t.amount, t.transaction_type)}
                  </td>
                  <td className="p-2">
                    <EditableTypeBadge
                      type={t.transaction_type}
                      onSave={(val) => updateTxn.mutate({ id: t.id, transaction_type: val })}
                    />
                  </td>
                  <td className="p-2 max-w-[140px]">
                    <div className="relative">
                      <InlineEdit
                        value={t.effective_category}
                        onSave={(val) => {
                          updateTxn.mutate({ id: t.id, category: val });
                          setRulePrompt({ tx: t, field: "category", newValue: val });
                        }}
                        type="select"
                        options={categoryOptions}
                      />
                      {t.category_override && (
                        <span className="absolute -left-2 top-1/2 -translate-y-1/2 w-1.5 h-1.5 bg-blue-500 rounded-full" title="Manually overridden" />
                      )}
                    </div>
                  </td>
                  <td className="p-2 text-zinc-400 whitespace-nowrap">{t.bank_name}</td>
                  <td className="p-2">
                    <div className="flex items-center gap-1 flex-wrap">
                      {t.tags?.map((tag) => (
                        <span
                          key={tag.id}
                          className="px-1.5 py-0.5 rounded text-xs font-medium text-white"
                          style={{ backgroundColor: tag.color + "99" }}
                        >
                          {tag.name}
                        </span>
                      ))}
                      <TagPicker transactionId={t.id} currentTags={t.tags ?? []} />
                    </div>
                  </td>
                  <td className="p-2">
                    <button
                      onClick={() => setSplitModal({ transactionId: t.id, amount: t.amount, description: t.description, merchant: t.effective_merchant || undefined, transactionIds: undefined })}
                      className="text-xs text-zinc-500 hover:text-zinc-200 px-2 py-0.5 rounded hover:bg-zinc-800 transition-colors"
                      title="Split this transaction"
                    >
                      Split
                    </button>
                  </td>
                </tr>
              ))
            )}
          </tbody>
        </table>
      </div>

      {/* Split modal */}
      {splitModal && (
        <SplitModal
          transactionId={splitModal.transactionId}
          transactionIds={splitModal.transactionIds}
          amount={splitModal.amount}
          description={splitModal.description}
          merchant={splitModal.merchant}
          onClose={() => { setSplitModal(null); if (splitModal.transactionIds) setSelected(new Set()); }}
        />
      )}

      {rulePrompt && (
        <SaveAsRulePrompt
          tx={rulePrompt.tx}
          field={rulePrompt.field}
          newValue={rulePrompt.newValue}
          onDone={() => setRulePrompt(null)}
        />
      )}

      {/* Pagination */}
      {data && data.total > filters.limit && (
        <div className="flex items-center justify-between mt-4">
          <span className="text-sm text-zinc-500">
            Showing {filters.offset + 1}-{Math.min(filters.offset + filters.limit, data.total)} of {data.total}
          </span>
          <div className="flex gap-2">
            <button
              disabled={currentPage <= 1}
              onClick={() => setPage(filters.offset - filters.limit)}
              className="px-3 py-1 bg-zinc-800 hover:bg-zinc-700 disabled:opacity-50 rounded text-sm"
            >
              Previous
            </button>
            <span className="px-3 py-1 text-sm text-zinc-400">
              Page {currentPage} of {totalPages}
            </span>
            <button
              disabled={currentPage >= totalPages}
              onClick={() => setPage(filters.offset + filters.limit)}
              className="px-3 py-1 bg-zinc-800 hover:bg-zinc-700 disabled:opacity-50 rounded text-sm"
            >
              Next
            </button>
          </div>
        </div>
      )}
    </div>
  );
}
