'use client';

import { useSearchParams } from 'next/navigation';
import { Suspense, useCallback, useEffect, useState } from 'react';
import Swal from 'sweetalert2';
import { RequireRole, useAuth } from '@/lib/auth-context';
import {
  Charge,
  CHARGE_STATUS_BADGES,
  CHARGE_STATUS_LABELS,
  ChargeStatus,
  createCharge,
  FinanceReport,
  getFinanceReport,
  listCharges,
  PAYMENT_METHOD_LABELS,
} from '@/lib/services/finance';
import ChargeModal from '@/components/app/finance/ChargeModal';
import PatientSelect from '@/components/app/PatientSelect';
import {
  EmptyState,
  ErrorAlert,
  Loading,
  Modal,
  PageHeader,
  Pagination,
  formatDate,
} from '@/components/app/ui';
import { extractApiError } from '@/lib/api-client';
import { formatCents, parseMoneyToCents } from '@/lib/money';

export default function FinanceiroPage() {
  return (
    <RequireRole roles={['admin', 'receptionist', 'dentist']}>
      <Suspense fallback={<Loading />}>
        <FinanceView />
      </Suspense>
    </RequireRole>
  );
}

function FinanceView() {
  const { user } = useAuth();
  // Dentista só vê o relatório da própria produção
  const isDentist = user?.role === 'dentist';
  const [tab, setTab] = useState<'charges' | 'report'>(isDentist ? 'report' : 'charges');

  return (
    <>
      <PageHeader title="Financeiro" subtitle="Cobranças, recebimentos e relatórios" />
      {!isDentist && (
        <ul className="nav nav-tabs mb-3">
          {[
            ['charges', 'Cobranças', 'bi-receipt'],
            ['report', 'Relatório', 'bi-graph-up'],
          ].map(([key, label, icon]) => (
            <li className="nav-item" key={key}>
              <button
                type="button"
                className={`nav-link ${tab === key ? 'active' : ''}`}
                onClick={() => setTab(key as 'charges' | 'report')}
              >
                <i className={`bi ${icon} me-1`} aria-hidden="true" />
                {label}
              </button>
            </li>
          ))}
        </ul>
      )}
      {tab === 'charges' && !isDentist ? <ChargesTab /> : <ReportTab ownOnly={isDentist} />}
    </>
  );
}

const PAGE_SIZE = 15;

function ChargesTab() {
  const { user } = useAuth();
  const searchParams = useSearchParams();
  const patientFilter = searchParams.get('patientId');

  const [items, setItems] = useState<Charge[]>([]);
  const [total, setTotal] = useState(0);
  const [totalPages, setTotalPages] = useState(1);
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState('');
  const [term, setTerm] = useState('');
  const [filter, setFilter] = useState<ChargeStatus | 'overdue' | 'open' | ''>('open');
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [selected, setSelected] = useState<number | null>(null);

  const [newOpen, setNewOpen] = useState(false);
  const [patientId, setPatientId] = useState<number | ''>('');
  const [description, setDescription] = useState('');
  const [amount, setAmount] = useState('');
  const [dueDate, setDueDate] = useState(() => new Date().toISOString().slice(0, 10));
  const [installments, setInstallments] = useState(1);
  const [saving, setSaving] = useState(false);
  const [formError, setFormError] = useState<string | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const status =
        filter === 'overdue' || filter === 'open' || filter === '' ? undefined : filter;
      const result = await listCharges({
        page,
        limit: PAGE_SIZE,
        search: term || undefined,
        status,
        open: filter === 'open' || undefined,
        overdue: filter === 'overdue' || undefined,
        patientId: patientFilter ? Number(patientFilter) : undefined,
      });
      setItems(result.data);
      setTotal(result.total);
      setTotalPages(Math.max(result.totalPages, 1));
    } catch (err) {
      setError(extractApiError(err));
    } finally {
      setLoading(false);
    }
  }, [page, term, filter, patientFilter]);

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

  async function handleCreate(e: React.FormEvent) {
    e.preventDefault();
    const amountCents = parseMoneyToCents(amount);
    if (!patientId) return setFormError('Selecione o paciente.');
    if (description.trim().length < 3) return setFormError('Descreva a cobrança.');
    if (!amountCents) return setFormError('Informe um valor válido.');
    setSaving(true);
    setFormError(null);
    try {
      await createCharge({ patientId, description: description.trim(), amountCents, dueDate, installments });
      setNewOpen(false);
      setDescription('');
      setAmount('');
      Swal.fire({ icon: 'success', title: 'Cobrança criada', timer: 1100, showConfirmButton: false });
      load();
    } catch (err) {
      setFormError(extractApiError(err));
    } finally {
      setSaving(false);
    }
  }

  return (
    <>
      <form
        className="row g-2 mb-3"
        onSubmit={(e) => {
          e.preventDefault();
          setPage(1);
          setTerm(search.trim());
        }}
      >
        <div className="col-12 col-md-4">
          <div className="input-group">
            <span className="input-group-text">
              <i className="bi bi-search" />
            </span>
            <input
              className="form-control"
              placeholder="Paciente ou descrição"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              aria-label="Buscar cobrança"
            />
          </div>
        </div>
        <div className="col-7 col-md-3">
          <select
            className="form-select"
            aria-label="Filtrar cobranças"
            value={filter}
            onChange={(e) => {
              setPage(1);
              setFilter(e.target.value as typeof filter);
            }}
          >
            <option value="open">A receber (em aberto + parcial)</option>
            <option value="overdue">Vencidas</option>
            <option value="">Todas</option>
            {(Object.keys(CHARGE_STATUS_LABELS) as ChargeStatus[]).map((s) => (
              <option key={s} value={s}>
                {CHARGE_STATUS_LABELS[s]}
              </option>
            ))}
          </select>
        </div>
        <div className="col-auto">
          <button className="btn btn-outline-primary" type="submit">
            Buscar
          </button>
        </div>
        <div className="col text-end">
          <button type="button" className="btn btn-primary" onClick={() => setNewOpen(true)}>
            <i className="bi bi-plus-lg me-1" />
            Nova cobrança
          </button>
        </div>
      </form>

      {patientFilter && (
        <div className="alert alert-light border py-2 small">
          Filtrando por um paciente. <a href="/painel/financeiro">Ver todos</a>
        </div>
      )}

      {error && <ErrorAlert message={error} onRetry={load} />}

      {loading ? (
        <Loading />
      ) : items.length === 0 ? (
        <EmptyState icon="bi-receipt" title="Nenhuma cobrança encontrada" />
      ) : (
        <div className="card border-0 shadow-sm">
          <div className="table-responsive">
            <table className="table table-hover align-middle mb-0">
              <thead className="table-light">
                <tr>
                  <th scope="col">Vencimento</th>
                  <th scope="col">Paciente</th>
                  <th scope="col">Descrição</th>
                  <th scope="col" className="text-end">Valor</th>
                  <th scope="col" className="text-end">Saldo</th>
                  <th scope="col">Status</th>
                  <th scope="col" className="text-end">Ações</th>
                </tr>
              </thead>
              <tbody>
                {items.map((charge) => (
                  <tr key={charge.id}>
                    <td className={`table-nowrap ${charge.isOverdue ? 'text-danger fw-semibold' : ''}`}>
                      {formatDate(`${charge.dueDate}T12:00:00`)}
                    </td>
                    <td className="fw-semibold">{charge.patient?.fullName}</td>
                    <td>{charge.description}</td>
                    <td className="text-end table-nowrap">{formatCents(charge.amountCents)}</td>
                    <td className="text-end table-nowrap">{formatCents(charge.balanceCents)}</td>
                    <td>
                      <span className={`badge ${CHARGE_STATUS_BADGES[charge.status]}`}>
                        {CHARGE_STATUS_LABELS[charge.status]}
                      </span>
                      {charge.isOverdue && <span className="badge text-bg-danger ms-1">Vencida</span>}
                    </td>
                    <td className="text-end">
                      <button
                        type="button"
                        className="btn btn-sm btn-outline-primary"
                        onClick={() => setSelected(charge.id)}
                        aria-label={`Abrir cobrança ${charge.description}`}
                      >
                        Abrir
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <div className="card-body pt-0">
            <Pagination page={page} totalPages={totalPages} total={total} onChange={setPage} />
          </div>
        </div>
      )}

      <ChargeModal
        chargeId={selected}
        isAdmin={user?.role === 'admin'}
        onClose={() => setSelected(null)}
        onChanged={load}
      />

      <Modal
        open={newOpen}
        title="Nova cobrança avulsa"
        onClose={() => setNewOpen(false)}
        busy={saving}
        footer={
          <>
            <button className="btn btn-outline-secondary" onClick={() => setNewOpen(false)} disabled={saving}>
              Cancelar
            </button>
            <button type="submit" form="charge-form" className="btn btn-primary" disabled={saving}>
              Criar
            </button>
          </>
        }
      >
        <form id="charge-form" onSubmit={handleCreate} noValidate>
          {formError && <div className="alert alert-danger py-2">{formError}</div>}
          <div className="mb-3">
            <label htmlFor="charge-patient" className="form-label">Paciente *</label>
            <PatientSelect id="charge-patient" value={patientId} onChange={setPatientId} />
          </div>
          <div className="mb-3">
            <label htmlFor="charge-desc" className="form-label">Descrição *</label>
            <input
              id="charge-desc"
              className="form-control"
              placeholder="Ex.: Consulta de avaliação"
              value={description}
              onChange={(e) => setDescription(e.target.value)}
            />
          </div>
          <div className="row g-3">
            <div className="col-4">
              <label htmlFor="charge-amount" className="form-label">Valor (R$) *</label>
              <input
                id="charge-amount"
                inputMode="decimal"
                className="form-control"
                value={amount}
                onChange={(e) => setAmount(e.target.value)}
              />
            </div>
            <div className="col-4">
              <label htmlFor="charge-due" className="form-label">1º vencimento</label>
              <input
                id="charge-due"
                type="date"
                className="form-control"
                value={dueDate}
                onChange={(e) => setDueDate(e.target.value)}
              />
            </div>
            <div className="col-4">
              <label htmlFor="charge-inst" className="form-label">Parcelas</label>
              <select
                id="charge-inst"
                className="form-select"
                value={installments}
                onChange={(e) => setInstallments(Number(e.target.value))}
              >
                {Array.from({ length: 12 }, (_, i) => i + 1).map((n) => (
                  <option key={n} value={n}>
                    {n === 1 ? 'À vista' : `${n}x`}
                  </option>
                ))}
              </select>
            </div>
          </div>
        </form>
      </Modal>
    </>
  );
}

function monthRange(offset = 0): { from: string; to: string } {
  const now = new Date();
  const first = new Date(now.getFullYear(), now.getMonth() + offset, 1);
  const last = new Date(now.getFullYear(), now.getMonth() + offset + 1, 0);
  const iso = (d: Date) =>
    `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
  return { from: iso(first), to: iso(last) };
}

function ReportTab({ ownOnly }: { ownOnly: boolean }) {
  const [range, setRange] = useState(() => monthRange());
  const [report, setReport] = useState<FinanceReport | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      setReport(await getFinanceReport(range.from, range.to));
    } catch (err) {
      setError(extractApiError(err));
    } finally {
      setLoading(false);
    }
  }, [range]);

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

  const maxMethod = Math.max(1, ...(report?.byMethod.map((m) => m.totalCents) ?? [1]));

  return (
    <>
      <div className="row g-2 align-items-end mb-4">
        <div className="col-6 col-md-3">
          <label htmlFor="rep-from" className="form-label small">De</label>
          <input
            id="rep-from"
            type="date"
            className="form-control"
            value={range.from}
            onChange={(e) => setRange({ ...range, from: e.target.value })}
          />
        </div>
        <div className="col-6 col-md-3">
          <label htmlFor="rep-to" className="form-label small">Até</label>
          <input
            id="rep-to"
            type="date"
            className="form-control"
            value={range.to}
            onChange={(e) => setRange({ ...range, to: e.target.value })}
          />
        </div>
        <div className="col-auto">
          <div className="btn-group">
            <button className="btn btn-outline-secondary" onClick={() => setRange(monthRange())}>
              Este mês
            </button>
            <button className="btn btn-outline-secondary" onClick={() => setRange(monthRange(-1))}>
              Mês anterior
            </button>
          </div>
        </div>
      </div>

      {ownOnly && (
        <div className="alert alert-light border small">
          Mostrando apenas a sua produção (cobranças dos seus planos de tratamento).
        </div>
      )}
      {error && <ErrorAlert message={error} onRetry={load} />}
      {loading || !report ? (
        <Loading />
      ) : (
        <>
          <div className="row g-3 mb-4">
            {[
              ['Recebido no período', report.receivedCents, `${report.paymentsCount} pagamento(s)`, 'success'],
              ['Estornos', report.refundsCents, `${report.refundsCount} estorno(s)`, 'secondary'],
              ['Líquido', report.netCents, 'recebido − estornos', 'primary'],
              ['A receber', report.receivableCents, `${report.receivableCount} cobrança(s) em aberto`, 'info'],
              ['Vencido', report.overdueCents, `${report.overdueCount} cobrança(s)`, 'danger'],
            ].map(([label, value, hint, color]) => (
              <div className="col-6 col-lg" key={label as string}>
                <div className={`card border-0 shadow-sm h-100 border-start border-4 border-${color}`}>
                  <div className="card-body">
                    <div className="small text-muted">{label}</div>
                    <div className="fs-5 fw-bold">{formatCents(value as number)}</div>
                    <small className="text-muted">{hint}</small>
                  </div>
                </div>
              </div>
            ))}
          </div>

          <div className="row g-4">
            <div className="col-lg-6">
              <div className="card border-0 shadow-sm h-100">
                <div className="card-header bg-white fw-semibold">Por forma de pagamento</div>
                <div className="card-body">
                  {report.byMethod.length === 0 ? (
                    <p className="text-muted mb-0">Nenhum recebimento no período.</p>
                  ) : (
                    report.byMethod
                      .sort((a, b) => b.totalCents - a.totalCents)
                      .map((m) => (
                        <div className="mb-3" key={m.method}>
                          <div className="d-flex justify-content-between small">
                            <span>
                              {PAYMENT_METHOD_LABELS[m.method]} <span className="text-muted">({m.count})</span>
                            </span>
                            <span className="fw-semibold">{formatCents(m.totalCents)}</span>
                          </div>
                          <div
                            className="progress"
                            role="progressbar"
                            aria-label={PAYMENT_METHOD_LABELS[m.method]}
                            aria-valuenow={Math.round((m.totalCents / maxMethod) * 100)}
                            aria-valuemin={0}
                            aria-valuemax={100}
                            style={{ height: 8 }}
                          >
                            <div className="progress-bar" style={{ width: `${(m.totalCents / maxMethod) * 100}%` }} />
                          </div>
                        </div>
                      ))
                  )}
                </div>
              </div>
            </div>
            <div className="col-lg-6">
              <div className="card border-0 shadow-sm h-100">
                <div className="card-header bg-white fw-semibold">Por dentista</div>
                <ul className="list-group list-group-flush">
                  {report.byDentist.length === 0 && (
                    <li className="list-group-item text-muted">Nenhum recebimento no período.</li>
                  )}
                  {report.byDentist
                    .sort((a, b) => b.totalCents - a.totalCents)
                    .map((d) => (
                      <li key={d.dentistId ?? 'none'} className="list-group-item d-flex justify-content-between">
                        <span>{d.dentistName}</span>
                        <span className="fw-semibold">{formatCents(d.totalCents)}</span>
                      </li>
                    ))}
                </ul>
              </div>
            </div>
          </div>
        </>
      )}
    </>
  );
}
