import { type DragEvent, useCallback, useEffect, useRef, useState } from 'react'
import { Link } from 'react-router-dom'
import { ApiHttpError } from '../../api/http'
import {
  createReimbursementBatch,
  downloadBatchCsv,
  downloadReimbursementsExport,
  fetchUnderProcessingWorkspace,
  postAdminCheckUpload,
  postBatchLock,
  postBatchUpdate,
  postMarkDonation,
  type UnderProcessingWorkspace,
} from '../../api/reimbursements'
import './underProcessing.css'

const currency = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })

type DragPayload =
  | { source: 'table'; itemId: number; reimbursementId?: number | null }
  | { source: 'batch'; itemId: number; fromBatchId: number; fromAdminId: number; reimbursementId?: number | null }

export function ReimbursementsUnderProcessingPage() {
  const [ws, setWs] = useState<UnderProcessingWorkspace | null>(null)
  const [err, setErr] = useState<string | null>(null)
  const [busy, setBusy] = useState(false)
  const [receiptModalUrl, setReceiptModalUrl] = useState<string | null>(null)
  const dragPayload = useRef<DragPayload | null>(null)

  const load = useCallback(() => {
    setErr(null)
    fetchUnderProcessingWorkspace()
      .then(setWs)
      .catch((e: unknown) =>
        setErr(e instanceof ApiHttpError ? e.message : 'Failed to load workspace.'),
      )
  }, [])

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

  async function persistToBatch(
    expenseId: number,
    batchId: number,
    adminId: number | null,
    reimbursementId?: number | null,
  ) {
    const form = new FormData()
    form.set('expense_id', String(expenseId))
    form.set('batch_id', String(batchId))
    form.set('batch_number', String(batchId))
    if (reimbursementId) form.set('reimbursement_id', String(reimbursementId))
    if (adminId != null && adminId !== 0) form.set('admin_id', String(adminId))
    else form.set('admin_id', '')
    await postBatchUpdate(form)
    load()
  }

  async function removeFromBatch(expenseId: number, reimbursementId?: number | null) {
    const form = new FormData()
    form.set('expense_id', String(expenseId))
    form.set('batch_id', '0')
    form.set('batch_number', '0')
    form.set('admin_id', '')
    if (reimbursementId) form.set('reimbursement_id', String(reimbursementId))
    await postBatchUpdate(form)
    load()
  }

  async function onMarkDonation(expenseId: number) {
    if (!confirm('Mark this expense as a donation? It will be removed from reimbursement batches.')) return
    const fd = new FormData()
    fd.set('expense_id', String(expenseId))
    try {
      await postMarkDonation(fd)
      load()
    } catch (e: unknown) {
      alert(e instanceof ApiHttpError ? e.message : 'Failed.')
    }
  }

  async function onAddBatch() {
    setBusy(true)
    try {
      await createReimbursementBatch()
      load()
    } catch (e: unknown) {
      alert(e instanceof ApiHttpError ? e.message : 'Could not create batch.')
    } finally {
      setBusy(false)
    }
  }

  async function onLockBatch(batchId: number) {
    const fd = new FormData()
    fd.set('batch_id', String(batchId))
    try {
      await postBatchLock(fd)
      load()
    } catch (e: unknown) {
      alert(e instanceof ApiHttpError ? e.message : 'Lock failed.')
    }
  }

  function onCheckUpload(batchId: number, adminId: number, file: File | null) {
    if (!file) return
    const fd = new FormData()
    fd.set('batch_id', String(batchId))
    fd.set('admin_id', String(adminId))
    fd.set('check_file', file)
    postAdminCheckUpload(fd)
      .then(() => load())
      .catch((e: unknown) => alert(e instanceof ApiHttpError ? e.message : 'Upload failed.'))
  }

  const pendingItems = ws?.pendingItems ?? []
  const batches = ws?.existingBatches ?? []
  const admins = ws?.adminUsers ?? []

  return (
    <div className="container-fluid mt-4 reimbursement-batch-page">
      {err ? <div className="alert alert-danger">{err}</div> : null}

      <div className="row reimb-layout">
        <div className="reimb-col reimb-col-list">
          <div className="card shadow-sm h-100">
            <div className="card-header d-flex flex-wrap gap-2 align-items-center">
              <div>
                <h5 className="mb-0">Reimbursements Under Processing</h5>
                <small className="text-muted">Drag items into a batch zone on the right.</small>
              </div>
              <div className="ms-auto d-flex flex-wrap gap-2">
                <button type="button" className="btn btn-primary btn-sm" disabled={busy} onClick={onAddBatch}>
                  Add New Batch
                </button>
                <Link to="/app/administrator/reimbursements" className="btn btn-sm btn-outline-secondary">
                  Reimbursement Main
                </Link>
                <button
                  type="button"
                  className="btn btn-sm btn-outline-success"
                  onClick={() =>
                    downloadReimbursementsExport({ type: 'under_processing' }).catch(() =>
                      alert('Export failed.'),
                    )
                  }
                >
                  Export CSV
                </button>
              </div>
            </div>
            <div className="card-body">
              <div className="reimb-table-scroll">
                <div className="table-responsive">
                  <table className="table table-bordered align-middle w-100 wrap-headers mb-0">
                    <thead className="table-light">
                      <tr>
                        <th>Expense Amount</th>
                        <th>Vendor</th>
                        <th>Description</th>
                        <th>Purchased By</th>
                        <th>Expense Receipt</th>
                        <th>Actions</th>
                      </tr>
                    </thead>
                    <tbody
                      className="reimb-draggable-table"
                      onDragOver={(e) => {
                        if (dragPayload.current?.source === 'batch') {
                          e.preventDefault()
                          e.currentTarget.classList.add('drag-over')
                        }
                      }}
                      onDragLeave={(e) => {
                        if (e.target === e.currentTarget) e.currentTarget.classList.remove('drag-over')
                      }}
                      onDrop={(e) => {
                        e.preventDefault()
                        e.currentTarget.classList.remove('drag-over')
                        const p = dragPayload.current
                        dragPayload.current = null
                        if (!p || p.source !== 'batch') return
                        void removeFromBatch(p.itemId, p.reimbursementId).catch((ex: unknown) =>
                          alert(ex instanceof ApiHttpError ? ex.message : 'Update failed.'),
                        )
                      }}
                    >
                      {pendingItems.length === 0 ? (
                        <tr>
                          <td colSpan={6} className="text-center text-muted py-4">
                            All reimbursements are currently assigned to a batch.
                          </td>
                        </tr>
                      ) : (
                        pendingItems.map((item) => {
                          const expenseId = Number(item.expense_id ?? item.id)
                          const amt = Number(item.expense_amount ?? item.amount ?? 0)
                          const reimbId = item.reimbursement_id
                            ? Number(item.reimbursement_id)
                            : null
                          const ru = item.receipt_url ? String(item.receipt_url) : ''
                          return (
                            <tr
                              key={expenseId}
                              draggable
                              onDragStart={(ev) => {
                                ev.dataTransfer.effectAllowed = 'move'
                                ev.dataTransfer.setData('text/plain', String(expenseId))
                                dragPayload.current = {
                                  source: 'table',
                                  itemId: expenseId,
                                  reimbursementId: reimbId,
                                }
                                ;(ev.currentTarget as HTMLElement).classList.add('dragging')
                              }}
                              onDragEnd={(ev) => {
                                ;(ev.currentTarget as HTMLElement).classList.remove('dragging')
                              }}
                            >
                              <td className="fw-semibold">{currency.format(amt)}</td>
                              <td>{String(item.vendor || 'N/A')}</td>
                              <td>{String(item.description || '-')}</td>
                              <td>{String(item.purchased_by || 'Unknown')}</td>
                              <td>
                                {ru ? (
                                  <button
                                    type="button"
                                    className="btn btn-link btn-sm p-0"
                                    onClick={() => setReceiptModalUrl(ru)}
                                  >
                                    View Receipt
                                  </button>
                                ) : (
                                  <span className="text-muted">N/A</span>
                                )}
                              </td>
                              <td>
                                <button
                                  type="button"
                                  className="btn btn-sm btn-outline-success"
                                  draggable={false}
                                  onClick={() => onMarkDonation(expenseId)}
                                >
                                  Mark as Donation
                                </button>
                              </td>
                            </tr>
                          )
                        })
                      )}
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>

        <div className="reimb-col reimb-col-batches">
          <div className="card shadow-sm h-100">
            <div className="card-header">
              <h5 className="mb-0">Active Batches</h5>
              <small className="text-muted">Each admin slot accepts drops from the table.</small>
            </div>
            <div className="card-body reimb-batches-scroll">
              {batches.length === 0 ? (
                <div className="alert alert-info py-2 px-3">No batches yet. Click &quot;Add New Batch&quot;.</div>
              ) : (
                <div className="reimb-batches-grid">
                  {batches.map((batch) => {
                    const batchId = Number(batch.batchNumber ?? batch.batch_id ?? batch.batchId ?? 0)
                    const statusRaw = String(batch.status ?? '').toLowerCase().trim()
                    const locked = statusRaw !== '' && statusRaw !== 'open'
                    const slots = (Array.isArray(batch.slots) ? batch.slots : []) as Array<
                      Record<string, unknown>
                    >
                    const sequence = Number(batch.sequence ?? batch.yearly_batch_number ?? batchId)
                    return (
                      <div key={batchId} className={`card batch-card ${locked ? 'batch-locked' : ''}`}>
                        <div className="card-header batch-header d-flex flex-wrap justify-content-between gap-2">
                          <div>
                            <strong>{String(batch.label ?? `Batch #${sequence || batchId}`)}</strong>
                            <div className="small text-muted">ID {batchId}</div>
                          </div>
                          <div className="d-flex gap-2">
                            <button
                              type="button"
                              className="btn btn-sm btn-outline-success"
                              onClick={() =>
                                downloadBatchCsv(batchId).catch(() => alert('Download failed.'))
                              }
                            >
                              Download CSV
                            </button>
                            {!locked ? (
                              <button
                                type="button"
                                className="btn btn-sm btn-outline-danger"
                                onClick={() => void onLockBatch(batchId)}
                              >
                                Submit Batch
                              </button>
                            ) : null}
                          </div>
                        </div>
                        <div className="card-body">
                          {slots.length === 0 ? (
                            <BatchDropZone
                              locked={locked}
                              onDrop={(e) => {
                                e.preventDefault()
                                const p = dragPayload.current
                                dragPayload.current = null
                                if (!p || p.source !== 'table') return
                                void persistToBatch(
                                  p.itemId,
                                  batchId,
                                  0,
                                  p.reimbursementId,
                                ).catch((ex: unknown) =>
                                  alert(ex instanceof ApiHttpError ? ex.message : 'Update failed.'),
                                )
                              }}
                            />
                          ) : (
                            slots.map((slot, idx) => {
                              const adminId = Number(slot.admin_id ?? slot.adminId ?? 0)
                              const label = String(
                                slot.admin_name ?? slot.adminName ?? `Admin #${adminId}`,
                              )
                              const itemIds = (Array.isArray(slot.items) ? slot.items : []) as number[]
                              const details = (slot.items_detail as Array<Record<string, unknown>> | undefined) ?? []
                              return (
                                <div key={`${batchId}-${idx}`} className="mb-3">
                                  <div className="small fw-semibold mb-1">{label}</div>
                                  <BatchDropZone
                                    locked={locked}
                                    onDrop={(e) => {
                                      e.preventDefault()
                                      const p = dragPayload.current
                                      dragPayload.current = null
                                      if (!p) return
                                      const reimb =
                                        p.source === 'table'
                                          ? p.reimbursementId
                                          : p.reimbursementId
                                      if (p.source === 'table') {
                                        void persistToBatch(
                                          p.itemId,
                                          batchId,
                                          adminId,
                                          reimb,
                                        ).catch((ex: unknown) =>
                                          alert(
                                            ex instanceof ApiHttpError ? ex.message : 'Update failed.',
                                          ),
                                        )
                                      } else {
                                        void persistToBatch(
                                          p.itemId,
                                          batchId,
                                          adminId,
                                          reimb,
                                        ).catch((ex: unknown) =>
                                          alert(
                                            ex instanceof ApiHttpError ? ex.message : 'Update failed.',
                                          ),
                                        )
                                      }
                                    }}
                                  />
                                  <div className="d-flex flex-column gap-2 mt-2 ps-1">
                                    {itemIds.map((eid) => {
                                      const row =
                                        details.find((x) => Number(x.expense_id ?? x.id) === eid) ?? {}
                                      const ru = row.receipt_url ? String(row.receipt_url) : ''
                                      const rmb = row.reimbursement_id
                                        ? Number(row.reimbursement_id)
                                        : null
                                      return (
                                        <div
                                          key={eid}
                                          className="batch-item"
                                          draggable={!locked}
                                          onDragStart={() => {
                                            dragPayload.current = {
                                              source: 'batch',
                                              itemId: eid,
                                              fromBatchId: batchId,
                                              fromAdminId: adminId,
                                              reimbursementId: rmb,
                                            }
                                          }}
                                          onDragEnd={() => {
                                            /* clear only after drop */
                                          }}
                                        >
                                          <div className="d-flex justify-content-between gap-2">
                                            <div>
                                              <div className="fw-semibold">
                                                {String(row.description ?? 'Item')}
                                              </div>
                                              <div className="small text-muted">
                                                {String(row.vendor ?? '')}
                                              </div>
                                            </div>
                                            <div className="text-end">
                                              <div>
                                                {currency.format(
                                                  Number(row.amount ?? row.expense_amount ?? 0),
                                                )}
                                              </div>
                                              {ru ? (
                                                <button
                                                  type="button"
                                                  className="btn btn-link btn-sm p-0"
                                                  onClick={() => setReceiptModalUrl(ru)}
                                                >
                                                  Receipt
                                                </button>
                                              ) : null}
                                            </div>
                                          </div>
                                        </div>
                                      )
                                    })}
                                  </div>
                                  {!locked ? (
                                    <div className="mt-2">
                                      <label className="form-label form-label-sm">Check file</label>
                                      <input
                                        type="file"
                                        className="form-control form-control-sm"
                                        accept=".pdf,image/*"
                                        onChange={(e) =>
                                          onCheckUpload(batchId, adminId, e.target.files?.[0] ?? null)
                                        }
                                      />
                                    </div>
                                  ) : null}
                                </div>
                              )
                            })
                          )}
                        </div>
                      </div>
                    )
                  })}
                </div>
              )}
            </div>
          </div>
        </div>
      </div>

      <div className="small text-muted mt-2">
        Admins:{' '}
        {admins.length
          ? admins.map((a) => `${a.firstname ?? ''} ${a.lastname ?? ''}`.trim()).join(', ')
          : '—'}
      </div>

      {receiptModalUrl ? (
        <div className="modal show d-block" tabIndex={-1} style={{ background: 'rgba(0,0,0,.35)' }}>
          <div className="modal-dialog modal-xl modal-dialog-scrollable">
            <div className="modal-content">
              <div className="modal-header">
                <h5 className="modal-title">Expense Receipt</h5>
                <button
                  type="button"
                  className="btn-close"
                  onClick={() => setReceiptModalUrl(null)}
                />
              </div>
              <div className="modal-body">
                <iframe className="receipt-viewer" src={receiptModalUrl} title="Receipt" />
              </div>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  )
}

function BatchDropZone(props: {
  locked: boolean
  onDrop: (e: DragEvent<HTMLDivElement>) => void
}) {
  const [over, setOver] = useState(false)
  if (props.locked) return null
  return (
    <div
      className={`batch-dropzone ${over ? 'drag-over' : ''}`}
      onDragOver={(e) => {
        e.preventDefault()
        setOver(true)
      }}
      onDragLeave={() => setOver(false)}
      onDrop={(e) => {
        setOver(false)
        props.onDrop(e)
      }}
    >
      <span className="text-muted small">Drop reimbursement row here</span>
    </div>
  )
}
