"use client";

import { useState } from "react";
import {
  useUpdateTransaction,
  useTags,
  useAddTransactionTag,
  useRemoveTransactionTag,
  useTransactionSplits,
  useTrips,
  useParticipants,
  useCurrentUser,
} from "@/lib/hooks";
import { SplitModal } from "./split-modal";
import { OrderDetails } from "./order-details";
import { CATEGORIES, formatCategory } from "@/lib/categories";
import type { TransactionRow, TagRow } from "@/lib/queries";

const TRANSACTION_TYPES = ["debit", "credit", "payment", "refund", "fee", "interest", "transfer"];
const SPEND_TYPES = new Set(["debit", "fee", "interest"]);

function formatAmount(amount: number, type: string) {
  const formatted = `$${Number(amount).toFixed(2)}`;
  return SPEND_TYPES.has(type) ? formatted : `+${formatted}`;
}

function InlineTags({ transactionId, initialTags }: { transactionId: number; initialTags: TagRow[] }) {
  const { data: allTags = [] } = useTags();
  const addTag = useAddTransactionTag();
  const removeTag = useRemoveTransactionTag();
  const [tags, setTags] = useState<TagRow[]>(initialTags);
  const [showPicker, setShowPicker] = useState(false);

  const available = allTags.filter((t) => !tags.find((ct) => ct.id === t.id));

  return (
    <div>
      <div className="flex flex-wrap gap-1 items-center">
        {tags.map((tag) => (
          <span
            key={tag.id}
            className="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium text-white"
            style={{ backgroundColor: tag.color + "99" }}
          >
            {tag.name}
            <button
              type="button"
              onClick={() => {
                removeTag.mutate({ transactionId, tagId: tag.id });
                setTags((prev) => prev.filter((t) => t.id !== tag.id));
              }}
              className="ml-0.5 text-white/60 hover:text-white leading-none"
            >
              ×
            </button>
          </span>
        ))}
        {available.length > 0 && (
          <button
            type="button"
            onClick={() => setShowPicker((v) => !v)}
            className="text-xs text-zinc-500 hover:text-zinc-300 px-1.5 py-0.5 rounded hover:bg-zinc-800"
          >
            + Add tag
          </button>
        )}
      </div>
      {showPicker && (
        <div className="mt-1.5 flex flex-wrap gap-1">
          {available.map((tag) => (
            <button
              key={tag.id}
              type="button"
              onClick={() => {
                addTag.mutate({ transactionId, tagId: tag.id });
                setTags((prev) => [...prev, tag]);
                setShowPicker(false);
              }}
              className="px-2 py-0.5 rounded text-xs font-medium text-white hover:brightness-125"
              style={{ backgroundColor: tag.color + "66" }}
            >
              {tag.name}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

export function EditTransactionModal({
  transaction,
  onClose,
}: {
  transaction: TransactionRow;
  onClose: () => void;
}) {
  const isManual = !transaction.statement_id;
  const updateTxn = useUpdateTransaction();
  const { data: trips = [] } = useTrips();
  const { data: participants = [] } = useParticipants();
  const { data: me } = useCurrentUser();

  // Editable override fields
  const [merchant, setMerchant] = useState(transaction.merchant_override ?? transaction.merchant_normalized ?? "");
  const [category, setCategory] = useState(transaction.effective_category ?? "");
  const [type, setType] = useState(transaction.transaction_type);
  const [notes, setNotes] = useState(transaction.notes ?? "");

  // Manual-only direct fields
  const [date, setDate] = useState(transaction.transaction_date?.slice(0, 10) ?? "");
  const [description, setDescription] = useState(transaction.description);
  const [amount, setAmount] = useState(String(transaction.amount));

  const [tripId, setTripId] = useState<number | null>(transaction.trip_id ?? null);
  const [ownerId, setOwnerId] = useState<number | null>(transaction.owner_id ?? null);

  // Splits — live via hook so they refresh after SplitModal saves
  const { data: liveSplits = [] } = useTransactionSplits(transaction.id);

  const [showSplitModal, setShowSplitModal] = useState(false);
  const [error, setError] = useState("");
  // Set when the API refuses an owner change that would hide the row from me.
  // Holding it in state (rather than confirm()) keeps the way out — add a
  // split — one click away instead of behind a dialog.
  const [releasePrompt, setReleasePrompt] = useState(false);

  const ownerChanged = ownerId !== null && ownerId !== (transaction.owner_id ?? null);
  const iHoldASplit = liveSplits.some(
    (s: { participant_id: number }) => s.participant_id === me?.id
  );

  async function handleSave(release = false) {
    setError("");
    try {
      const patch: Parameters<typeof updateTxn.mutateAsync>[0] = { id: transaction.id };

      // Override fields (always)
      if (merchant !== (transaction.merchant_override ?? transaction.merchant_normalized ?? ""))
        patch.merchant_normalized = merchant;
      if (category !== (transaction.effective_category ?? ""))
        patch.category = category;
      if (type !== transaction.transaction_type)
        patch.transaction_type = type;
      if (notes !== (transaction.notes ?? ""))
        patch.notes = notes;

      // Direct fields (manual only)
      if (isManual) {
        if (date !== transaction.transaction_date?.slice(0, 10))
          patch.transaction_date = date;
        if (description !== transaction.description)
          patch.description = description;
        if (parseFloat(amount) !== transaction.amount)
          patch.amount = parseFloat(amount);
      }

      if (tripId !== (transaction.trip_id ?? null))
        patch.trip_id = tripId;

      // Owner is manual-only: a statement row's owner comes from its statement.
      if (isManual && ownerChanged) {
        patch.owner_id = ownerId!;
        if (release) patch.release = true;
      }

      await updateTxn.mutateAsync(patch);
      onClose();
    } catch (e) {
      if ((e as { code?: string })?.code === "would_lose_access") {
        setReleasePrompt(true);
      }
      setError(e instanceof Error ? e.message : "Failed to save");
    }
  }

  return (
    <>
      <div className="fixed inset-0 z-40 flex items-center justify-center bg-black/60" onClick={onClose}>
        <div
          className="bg-zinc-900 border border-zinc-700 rounded-xl w-full max-w-lg mx-4 shadow-2xl flex flex-col max-h-[90vh]"
          onClick={(e) => e.stopPropagation()}
        >
          {/* Header */}
          <div className="px-6 pt-5 pb-4 border-b border-zinc-800">
            <h3 className="font-semibold text-sm text-zinc-300">Edit Transaction</h3>
            <p className="text-xs text-zinc-500 mt-0.5">{transaction.bank_name}</p>
          </div>

          <div className="overflow-y-auto flex-1 px-6 py-4 space-y-5">

            {/* Core fields — read-only for statement, editable for manual */}
            {isManual ? (
              <div className="space-y-3">
                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <label className="block text-xs text-zinc-500 mb-1">Date</label>
                    <input
                      type="date"
                      value={date}
                      onChange={(e) => setDate(e.target.value)}
                      className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
                    />
                  </div>
                  <div>
                    <label className="block text-xs text-zinc-500 mb-1">Amount</label>
                    <input
                      type="number"
                      step="0.01"
                      value={amount}
                      onChange={(e) => setAmount(e.target.value)}
                      className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
                    />
                  </div>
                </div>
                <div>
                  <label className="block text-xs text-zinc-500 mb-1">Description</label>
                  <input
                    value={description}
                    onChange={(e) => setDescription(e.target.value)}
                    className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
                  />
                </div>
              </div>
            ) : (
              <div className="bg-zinc-800/50 rounded-lg px-3 py-2.5 space-y-1">
                <p className="text-sm font-medium">{transaction.description}</p>
                <p className={`text-sm font-mono ${SPEND_TYPES.has(transaction.transaction_type) ? "text-red-400" : "text-green-400"}`}>
                  {formatAmount(transaction.amount, transaction.transaction_type)}
                </p>
                <p className="text-xs text-zinc-500">
                  {new Date(transaction.transaction_date).toLocaleDateString("en-AU", { day: "numeric", month: "short", year: "numeric" })}
                </p>
              </div>
            )}

            {/* Override fields */}
            <div className="space-y-3">
              <div className="grid grid-cols-2 gap-3">
                <div>
                  <label className="block text-xs text-zinc-500 mb-1">Type</label>
                  <select
                    value={type}
                    onChange={(e) => setType(e.target.value)}
                    className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
                  >
                    {TRANSACTION_TYPES.map((t) => (
                      <option key={t} value={t}>{t}</option>
                    ))}
                  </select>
                </div>
                <div>
                  <label className="block text-xs text-zinc-500 mb-1">Category</label>
                  <select
                    value={category}
                    onChange={(e) => setCategory(e.target.value)}
                    className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
                  >
                    <option value="">— none —</option>
                    {CATEGORIES.map((c) => (
                      <option key={c} value={c}>{formatCategory(c)}</option>
                    ))}
                  </select>
                </div>
              </div>

              <div>
                <label className="block text-xs text-zinc-500 mb-1">Merchant</label>
                <input
                  value={merchant}
                  onChange={(e) => setMerchant(e.target.value)}
                  placeholder="Normalized merchant name"
                  className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
                />
              </div>

              <div>
                <label className="block text-xs text-zinc-500 mb-1">Notes</label>
                <textarea
                  value={notes}
                  onChange={(e) => setNotes(e.target.value)}
                  rows={3}
                  placeholder="Additional context about this transaction…"
                  className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm resize-none"
                />
              </div>
            </div>

            {/* Trip */}
            <div>
              <label className="block text-xs text-zinc-500 mb-1">Trip</label>
              <select
                value={tripId ?? ""}
                onChange={(e) => setTripId(e.target.value ? Number(e.target.value) : null)}
                className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
              >
                <option value="">— No Trip —</option>
                {trips.filter((t) => !t.archived).map((t) => (
                  <option key={t.id} value={t.id}>{t.name}</option>
                ))}
              </select>
            </div>

            {/* Tags */}
            <div>
              <p className="text-xs text-zinc-500 mb-1.5">Tags</p>
              <InlineTags transactionId={transaction.id} initialTags={transaction.tags ?? []} />
            </div>

            {/* Paid by — sits next to Splits deliberately: together they are
                whose money went out and whose share it was. */}
            <div>
              <label className="block text-xs text-zinc-500 mb-1">Paid by</label>
              {isManual ? (
                <>
                  <select
                    value={ownerId ?? ""}
                    onChange={(e) => {
                      setOwnerId(e.target.value ? Number(e.target.value) : null);
                      setReleasePrompt(false);
                      setError("");
                    }}
                    className="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1.5 text-sm"
                  >
                    {participants.map((p) => (
                      <option key={p.id} value={p.id}>{p.name}</option>
                    ))}
                  </select>
                  {ownerChanged && (
                    <p className="text-xs text-amber-400/90 mt-1.5">
                      {ownerId === me?.id
                        ? "This moves the spend onto your ledger, and any split you hold becomes their share of it."
                        : iHoldASplit
                          ? "This moves the spend onto their ledger. Your split becomes what you owe them rather than what they owe you."
                          : "You hold no split on this. Add one first, or it leaves your view for good."}
                    </p>
                  )}
                </>
              ) : (
                <div className="bg-zinc-800/50 rounded px-2 py-1.5">
                  <p className="text-sm text-zinc-300">{transaction.owner_name ?? "—"}</p>
                  <p className="text-xs text-zinc-500 mt-0.5">
                    From a statement, so the owner is the statement&apos;s. Change it on the
                    Statements page to move every row on that statement.
                  </p>
                </div>
              )}
            </div>

            {/* Splits */}
            <div>
              <div className="flex items-center justify-between mb-1.5">
                <p className="text-xs text-zinc-500">Splits</p>
                <button
                  type="button"
                  onClick={() => setShowSplitModal(true)}
                  className="text-xs text-blue-400 hover:text-blue-300"
                >
                  {liveSplits.length > 0 ? "Edit splits" : "Add split"}
                </button>
              </div>
              {liveSplits.length > 0 ? (
                <div className="flex flex-wrap gap-1">
                  {liveSplits.map((s: { participant_id: number; name: string; share_percent: number; settled: boolean }) => (
                    <span
                      key={s.participant_id}
                      className={`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs ${
                        s.settled ? "bg-zinc-800 text-zinc-500" : "bg-amber-900/40 text-amber-300"
                      }`}
                    >
                      {s.name} {s.share_percent}%
                      {s.settled && <span className="text-emerald-500">✓</span>}
                    </span>
                  ))}
                </div>
              ) : (
                <p className="text-xs text-zinc-600 italic">No splits</p>
              )}
            </div>

            <OrderDetails transactionId={transaction.id} currency={transaction.currency ?? null} />

          </div>

          {/* Footer */}
          <div className="px-6 py-4 border-t border-zinc-800 space-y-3">
            {error && <p className="text-red-400 text-xs">{error}</p>}
            {/* The refusal names the step that was skipped, so offer both: add
                the split (keeps the row reachable and gets the balance right)
                or hand it over knowingly. */}
            {releasePrompt && (
              <div className="flex flex-wrap gap-2">
                <button
                  type="button"
                  onClick={() => setShowSplitModal(true)}
                  className="px-3 py-1.5 bg-zinc-800 hover:bg-zinc-700 text-zinc-200 rounded-lg text-xs"
                >
                  Add my split first
                </button>
                <button
                  type="button"
                  onClick={() => handleSave(true)}
                  disabled={updateTxn.isPending}
                  className="px-3 py-1.5 bg-amber-700 hover:bg-amber-600 disabled:opacity-50 text-white rounded-lg text-xs"
                >
                  Give it away anyway
                </button>
              </div>
            )}
            <div className="flex gap-2 justify-end">
              <button
                type="button"
                onClick={onClose}
                className="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-zinc-300 rounded-lg text-sm"
              >
                Cancel
              </button>
              <button
                type="button"
                onClick={() => handleSave()}
                disabled={updateTxn.isPending}
                className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white rounded-lg text-sm font-medium"
              >
                {updateTxn.isPending ? "Saving…" : "Save"}
              </button>
            </div>
          </div>
        </div>
      </div>

      {showSplitModal && (
        <SplitModal
          transactionId={transaction.id}
          amount={transaction.amount}
          description={transaction.description}
          merchant={transaction.effective_merchant || undefined}
          onClose={() => setShowSplitModal(false)}
        />
      )}
    </>
  );
}
