import { useCallback, useEffect, useState } from 'react';
import {
  api,
  type FollowUp,
  type PendingNda,
  type Staff,
  type Today as TodayData,
  type Todo,
} from '../api.js';
import { DEAL_LABELS, Dialog, Panel, StatusBadge, formatDay } from '../components.js';
import { TodoRow } from '../workflow.js';

const INPUT = 'w-full rounded border border-gray-300 px-2 py-1 text-sm';

/** Groups anything with a person attached, for the team tab. */
function groupBy<T>(rows: T[], name: (row: T) => string): [string, T[]][] {
  const groups = new Map<string, T[]>();
  for (const row of rows) {
    const key = name(row);
    groups.set(key, [...(groups.get(key) ?? []), row]);
  }
  return [...groups.entries()].sort((a, b) => a[0].localeCompare(b[0]));
}

export default function Today({
  staff,
  onOpenBuyer,
  onOpenBusiness,
  onChanged,
}: {
  staff: Staff;
  onOpenBuyer: (id: string) => void;
  onOpenBusiness: (id: string) => void;
  /** Lets the nav badge follow along after every action. */
  onChanged: () => void;
}) {
  const [team, setTeam] = useState(false);
  const [data, setData] = useState<TodayData | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [followUp, setFollowUp] = useState<FollowUp | null>(null);
  const [ending, setEnding] = useState<FollowUp | null>(null);

  const load = useCallback(
    () =>
      api
        .today(team ? undefined : staff.id)
        .then((res) => {
          setData(res);
          setError(null);
        })
        .catch((err: Error) => setError(err.message)),
    [team, staff.id],
  );

  useEffect(() => {
    void load();
  }, [load]);

  async function refresh() {
    await load();
    onChanged();
  }

  const empty =
    data &&
    data.todos.length === 0 &&
    data.follow_ups.length === 0 &&
    data.pending_ndas.length === 0;

  return (
    <div className="flex flex-col gap-4">
      <div className="flex items-center justify-between">
        <div className="flex gap-1">
          {[
            { label: 'My day', value: false },
            { label: 'Team', value: true },
          ].map((tab) => (
            <button
              key={tab.label}
              onClick={() => setTeam(tab.value)}
              className={`rounded px-3 py-1.5 text-sm ${
                team === tab.value
                  ? 'bg-gray-900 text-white'
                  : 'border border-gray-300 bg-white hover:bg-gray-100'
              }`}
            >
              {tab.label}
            </button>
          ))}
        </div>
        {data && (
          <span className="text-sm text-gray-500">
            {data.counts.overdue_todos > 0 && (
              <span className="font-medium text-red-600">{data.counts.overdue_todos} overdue</span>
            )}
            {data.counts.overdue_todos > 0 && ' · '}
            {data.counts.total} item{data.counts.total === 1 ? '' : 's'}
          </span>
        )}
      </div>

      {error && <p className="text-sm text-red-600">{error}</p>}

      {empty && (
        <div className="rounded border border-gray-200 bg-white px-4 py-10 text-center text-sm text-gray-500">
          Nothing due. Enjoy your coffee.
        </div>
      )}

      {data && data.todos.length > 0 && (
        <Panel title="Todos">
          {team ? (
            groupBy(data.todos, (todo) => todo.assigned_to.name).map(([name, todos]) => (
              <div key={name} className="mb-2 last:mb-0">
                <p className="text-xs font-medium uppercase tracking-wide text-gray-500">{name}</p>
                <TodoList todos={todos} onChanged={refresh} open={{ onOpenBuyer, onOpenBusiness }} />
              </div>
            ))
          ) : (
            <TodoList todos={data.todos} onChanged={refresh} open={{ onOpenBuyer, onOpenBusiness }} />
          )}
        </Panel>
      )}

      {data && data.follow_ups.length > 0 && (
        <Panel title="Follow-ups due">
          {team ? (
            groupBy(data.follow_ups, (row) => row.created_by_name ?? 'unassigned').map(
              ([name, rows]) => (
                <div key={name} className="mb-2 last:mb-0">
                  <p className="text-xs font-medium uppercase tracking-wide text-gray-500">{name}</p>
                  {rows.map((row) => (
                    <FollowUpRow
                      key={row.id}
                      row={row}
                      onOpenBuyer={onOpenBuyer}
                      onOpenBusiness={onOpenBusiness}
                      onFollowUp={setFollowUp}
                      onEnd={setEnding}
                    />
                  ))}
                </div>
              ),
            )
          ) : (
            data.follow_ups.map((row) => (
              <FollowUpRow
                key={row.id}
                row={row}
                onOpenBuyer={onOpenBuyer}
                onOpenBusiness={onOpenBusiness}
                onFollowUp={setFollowUp}
                onEnd={setEnding}
              />
            ))
          )}
        </Panel>
      )}

      {data && data.pending_ndas.length > 0 && (
        <Panel title="NDA signatures pending">
          {data.pending_ndas.map((row) => (
            <PendingNdaRow key={row.id} row={row} team={team} onOpenBuyer={onOpenBuyer} />
          ))}
        </Panel>
      )}

      {followUp && (
        <FollowUpDialog
          row={followUp}
          onClose={() => setFollowUp(null)}
          onDone={() => {
            setFollowUp(null);
            void refresh();
          }}
        />
      )}
      {ending && (
        <EndDealDialog
          row={ending}
          onClose={() => setEnding(null)}
          onDone={() => {
            setEnding(null);
            void refresh();
          }}
        />
      )}
    </div>
  );
}

function TodoList({
  todos,
  onChanged,
  open,
}: {
  todos: (Todo & { overdue?: boolean })[];
  onChanged: () => void;
  open: { onOpenBuyer: (id: string) => void; onOpenBusiness: (id: string) => void };
}) {
  return (
    <ul className="flex flex-col">
      {todos.map((todo) => (
        <TodoRow
          key={todo.id}
          todo={todo}
          onChanged={onChanged}
          onOpenContext={(context) => {
            // Deals and rounds live on the buyer page, so that wins when both exist.
            if (context.buyer_id) open.onOpenBuyer(context.buyer_id);
            else if (context.business_id) open.onOpenBusiness(context.business_id);
          }}
        />
      ))}
    </ul>
  );
}

function FollowUpRow({
  row,
  onOpenBuyer,
  onOpenBusiness,
  onFollowUp,
  onEnd,
}: {
  row: FollowUp;
  onOpenBuyer: (id: string) => void;
  onOpenBusiness: (id: string) => void;
  onFollowUp: (row: FollowUp) => void;
  onEnd: (row: FollowUp) => void;
}) {
  return (
    <div className="flex flex-wrap items-center gap-2 border-b border-gray-100 py-2 text-sm last:border-0">
      <span className="min-w-0 flex-1">
        <button onClick={() => onOpenBuyer(row.buyer_id)} className="text-blue-600 hover:underline">
          {row.buyer_name}
        </button>{' '}
        about{' '}
        <button
          onClick={() => onOpenBusiness(row.business_id)}
          className="text-blue-600 hover:underline"
        >
          {row.business_name}
        </button>
        , info sent <span className="text-gray-500">{formatDay(row.follow_up_at)}</span>
      </span>
      <StatusBadge status={row.status} label={DEAL_LABELS[row.status]} />
      <button
        onClick={() => onFollowUp(row)}
        className="rounded border border-gray-300 bg-white px-2 py-1 text-xs hover:bg-gray-100"
      >
        Follow-up sent…
      </button>
      <button
        onClick={() => onEnd(row)}
        className="rounded border border-gray-300 bg-white px-2 py-1 text-xs hover:bg-gray-100"
      >
        End deal…
      </button>
    </div>
  );
}

function PendingNdaRow({
  row,
  team,
  onOpenBuyer,
}: {
  row: PendingNda;
  team: boolean;
  onOpenBuyer: (id: string) => void;
}) {
  return (
    <div className="flex items-center gap-2 border-b border-gray-100 py-2 text-sm last:border-0">
      <span className="flex-1">
        <button onClick={() => onOpenBuyer(row.buyer_id)} className="text-blue-600 hover:underline">
          {row.buyer_name}
        </button>
        , sent <span className="text-gray-500">{formatDay(row.sent_at)}</span>
      </span>
      {team && <span className="text-xs text-gray-500">{row.created_by_name ?? '—'}</span>}
    </div>
  );
}

/** "Follow-up sent" always writes a note; the choice is whether to keep waiting. */
function FollowUpDialog({
  row,
  onClose,
  onDone,
}: {
  row: FollowUp;
  onClose: () => void;
  onDone: () => void;
}) {
  const [comment, setComment] = useState('');
  const [rearm, setRearm] = useState(true);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function confirm() {
    setBusy(true);
    try {
      await api.followUpSent(row.id, comment, rearm);
      onDone();
    } catch (err) {
      setError((err as Error).message);
      setBusy(false);
    }
  }

  return (
    <Dialog title="Follow-up sent" confirmLabel="Save" busy={busy} onConfirm={confirm} onCancel={onClose}>
      <p className="mb-2 text-sm text-gray-600">
        {row.buyer_name} about {row.business_name}
      </p>
      <textarea
        rows={3}
        value={comment}
        onChange={(e) => setComment(e.target.value)}
        placeholder="Comment (optional) — saved as a note"
        className={INPUT}
      />
      <div className="mt-2 flex flex-col gap-1 text-sm">
        {[
          { value: true, label: 'Wait another 14 days' },
          { value: false, label: 'Stop waiting' },
        ].map((option) => (
          <label key={String(option.value)} className="flex items-center gap-2">
            <input
              type="radio"
              checked={rearm === option.value}
              onChange={() => setRearm(option.value)}
            />
            {option.label}
          </label>
        ))}
      </div>
      {error && <p className="mt-2 text-sm text-red-600">{error}</p>}
    </Dialog>
  );
}

/** The normal status change, preset to ENDED. */
function EndDealDialog({
  row,
  onClose,
  onDone,
}: {
  row: FollowUp;
  onClose: () => void;
  onDone: () => void;
}) {
  const [comment, setComment] = useState('');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function confirm() {
    setBusy(true);
    try {
      await api.setDealStatus(row.id, 'ENDED', comment);
      onDone();
    } catch (err) {
      setError((err as Error).message);
      setBusy(false);
    }
  }

  return (
    <Dialog title="End deal" confirmLabel="Confirm" busy={busy} onConfirm={confirm} onCancel={onClose}>
      <p className="mb-2 text-sm text-gray-600">
        {row.business_name}: {DEAL_LABELS[row.status]} → {DEAL_LABELS.ENDED}
      </p>
      <textarea
        rows={3}
        value={comment}
        onChange={(e) => setComment(e.target.value)}
        placeholder="Comment (optional) — saved as a note"
        className={INPUT}
      />
      {error && <p className="mt-2 text-sm text-red-600">{error}</p>}
    </Dialog>
  );
}
