import { useCallback, useEffect, useMemo, useState } from 'react'
import {
  addContactLog,
  deleteContactLog,
  deleteReport,
  getContactLogs,
  getProjects,
  getReports,
  reportDownloadUrl,
  updateContactLog,
  uploadReport,
  type ContactLog,
  type OrgReport,
  type ProjectRow,
} from '../api/client'
import { stageLabel } from '../stages'
import HelpButton from '../help/HelpButton'

/**
 * 사업관리 화면. 3단계 법률검토로 진행할 기관 현황을 한 표로 모아 보고, 기관을 고르면
 * "신청 확인 연락" 이력과 최종 보고서를 다룬다(요청자 요구: 별도 메뉴 + 연락 이력관리 +
 * 기관별 최종 보고서 업로드).
 *
 * 기관 현황 숫자는 대시보드와 같은 집계를 그대로 받아 쓴다 - 두 화면 숫자가 어긋나지 않게.
 */

interface Props {
  /** 기관명을 클릭했을 때 기관관리 화면으로 넘긴다. */
  onOpenOrg: (orgId: number) => void
}

const METHODS = ['전화', '메일', '방문', '기타']

function formatDateTime(ms: number): string {
  const d = new Date(ms)
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}

function formatSize(bytes: number): string {
  if (bytes < 1024) {
    return `${bytes} B`
  }
  if (bytes < 1024 * 1024) {
    return `${Math.round(bytes / 1024)} KB`
  }
  return `${(bytes / 1024 / 1024).toFixed(1)} MB`
}

/** 오늘 날짜를 yyyy-MM-dd로. 연락 이력 입력의 기본값이다. */
function today(): string {
  const d = new Date()
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`
}

export default function ProjectsPage({ onOpenOrg }: Props) {
  const [rows, setRows] = useState<ProjectRow[] | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [keyword, setKeyword] = useState('')
  const [stageFilter, setStageFilter] = useState('')
  const [contactFilter, setContactFilter] = useState('')

  /** 오른쪽 상세 패널에서 다루는 기관. */
  const [selected, setSelected] = useState<ProjectRow | null>(null)
  const [logs, setLogs] = useState<ContactLog[]>([])
  const [reports, setReports] = useState<OrgReport[]>([])
  const [panelBusy, setPanelBusy] = useState(false)
  const [panelError, setPanelError] = useState<string | null>(null)

  const [logDate, setLogDate] = useState(today())
  const [logMethod, setLogMethod] = useState(METHODS[0])
  const [logSummary, setLogSummary] = useState('')
  const [editingLogId, setEditingLogId] = useState<number | null>(null)

  const reload = useCallback(async () => {
    try {
      setRows(await getProjects())
      setError(null)
    } catch (e) {
      setError((e as Error).message)
    }
  }, [])

  useEffect(() => {
    void reload()
  }, [reload])

  const visible = useMemo(() => {
    const kw = keyword.trim()
    return (rows ?? []).filter((row) => {
      if (kw && !row.org.orgName.includes(kw) && !row.org.orgNo.includes(kw)) {
        return false
      }
      if (stageFilter && String(row.org.stage ?? '') !== stageFilter) {
        return false
      }
      if (contactFilter === 'none' && row.contactCount > 0) {
        return false
      }
      if (contactFilter === 'some' && row.contactCount === 0) {
        return false
      }
      return true
    })
  }, [rows, keyword, stageFilter, contactFilter])

  async function openPanel(row: ProjectRow) {
    setSelected(row)
    setPanelError(null)
    setEditingLogId(null)
    setLogSummary('')
    setLogDate(today())
    setPanelBusy(true)
    try {
      const [logList, reportList] = await Promise.all([
        getContactLogs(row.org.id),
        getReports(row.org.id),
      ])
      setLogs(logList)
      setReports(reportList)
    } catch (e) {
      setPanelError((e as Error).message)
    } finally {
      setPanelBusy(false)
    }
  }

  async function submitLog() {
    if (!selected || logSummary.trim() === '' || panelBusy) {
      return
    }
    setPanelBusy(true)
    setPanelError(null)
    try {
      const body = { contactedOn: logDate, method: logMethod, summary: logSummary.trim() }
      const next = editingLogId
        ? await updateContactLog(selected.org.id, editingLogId, body)
        : await addContactLog(selected.org.id, body)
      setLogs(next)
      setLogSummary('')
      setEditingLogId(null)
      await reload()
    } catch (e) {
      setPanelError((e as Error).message)
    } finally {
      setPanelBusy(false)
    }
  }

  async function removeLog(log: ContactLog) {
    if (!selected || !window.confirm('이 연락 이력을 삭제할까요?')) {
      return
    }
    setPanelBusy(true)
    try {
      await deleteContactLog(selected.org.id, log.id)
      setLogs((prev) => prev.filter((l) => l.id !== log.id))
      await reload()
    } catch (e) {
      setPanelError((e as Error).message)
    } finally {
      setPanelBusy(false)
    }
  }

  async function handleReportUpload(file: File) {
    if (!selected) {
      return
    }
    setPanelBusy(true)
    setPanelError(null)
    try {
      setReports(await uploadReport(selected.org.id, file))
      await reload()
    } catch (e) {
      setPanelError((e as Error).message)
    } finally {
      setPanelBusy(false)
    }
  }

  async function removeReport(report: OrgReport) {
    if (!selected || !window.confirm(`"${report.fileName}"을 삭제할까요?`)) {
      return
    }
    setPanelBusy(true)
    try {
      await deleteReport(selected.org.id, report.id)
      setReports((prev) => prev.filter((r) => r.id !== report.id))
      await reload()
    } catch (e) {
      setPanelError((e as Error).message)
    } finally {
      setPanelBusy(false)
    }
  }

  if (error && !rows) {
    return (
      <div className="flex flex-col items-center gap-3 p-8 text-sm">
        <p className="text-red-600">{error}</p>
        <button
          type="button"
          onClick={() => void reload()}
          className="rounded-md border border-gray-300 px-3 py-1.5"
        >
          다시 시도
        </button>
      </div>
    )
  }

  return (
    <div className="space-y-4 p-6">
      <section className="rounded-lg border border-gray-200 bg-white p-5">
        <h1 className="flex items-center gap-1.5 text-lg font-semibold">
          사업관리
          <HelpButton topic="projects.overview" />
        </h1>
        <p className="text-xs text-gray-500">
          3단계 법률검토 대상 기관 현황과 신청 확인 연락 이력, 최종 보고서를 관리합니다.
        </p>

        <div className="mt-4 flex flex-wrap gap-2">
          <input
            aria-label="기관명/기관코드 검색"
            placeholder="기관명/기관코드 검색"
            value={keyword}
            onChange={(e) => setKeyword(e.target.value)}
            className="min-w-48 flex-1 rounded-md border border-gray-300 px-2 py-1.5 text-sm"
          />
          <select
            aria-label="현재 단계"
            value={stageFilter}
            onChange={(e) => setStageFilter(e.target.value)}
            className="rounded-md border border-gray-300 px-2 py-1.5 text-sm"
          >
            <option value="">현재 단계 전체</option>
            {Array.from({ length: 12 }, (_, i) => i + 1).map((n) => (
              <option key={n} value={String(n)}>{`${n}. ${stageLabel(n)}`}</option>
            ))}
          </select>
          <select
            aria-label="연락 이력"
            value={contactFilter}
            onChange={(e) => setContactFilter(e.target.value)}
            className="rounded-md border border-gray-300 px-2 py-1.5 text-sm"
          >
            <option value="">연락 이력 전체</option>
            <option value="some">이력 있음</option>
            <option value="none">이력 없음</option>
          </select>
        </div>

        <div className="mt-3 overflow-x-auto">
          <table data-testid="project-table" className="w-full min-w-[1000px] text-sm">
            <thead>
              <tr className="border-b border-gray-200 text-xs text-gray-500">
                <th className="px-2 py-2 text-left font-normal">연번</th>
                <th className="px-2 py-2 text-left font-normal">기관명</th>
                <th className="px-2 py-2 text-left font-normal">현재 단계</th>
                <th className="px-2 py-2 text-left font-normal">문정원 담당</th>
                <th className="px-2 py-2 text-left font-normal">담당 변호사</th>
                <th className="px-2 py-2 text-right font-normal">권리확인</th>
                <th className="px-2 py-2 text-right font-normal">권리처리</th>
                <th className="px-2 py-2 text-right font-normal">최근 연락</th>
                <th className="px-2 py-2 text-right font-normal">보고서</th>
                <th className="px-2 py-2 text-right font-normal">관리</th>
              </tr>
            </thead>
            <tbody>
              {rows === null ? (
                <tr>
                  <td colSpan={10} className="px-2 py-6 text-center text-sm text-gray-500">
                    불러오는 중…
                  </td>
                </tr>
              ) : visible.length === 0 ? (
                <tr>
                  <td colSpan={10} className="px-2 py-6 text-center text-sm text-gray-500">
                    조건에 맞는 기관이 없습니다.
                  </td>
                </tr>
              ) : (
                visible.map((row) => (
                  <tr key={row.org.id} className="border-b border-gray-100 hover:bg-gray-50">
                    <td className="px-2 py-2 text-gray-500 tabular-nums">{row.org.orgNo}</td>
                    <td className="px-2 py-2">
                      <button
                        type="button"
                        onClick={() => onOpenOrg(row.org.id)}
                        className="font-medium text-blue-700 hover:underline"
                      >
                        {row.org.orgName}
                      </button>
                    </td>
                    <td className="px-2 py-2 text-gray-600">
                      {row.org.stage === null ? '단계 미지정' : `${row.org.stage}. ${stageLabel(row.org.stage)}`}
                    </td>
                    <td className="px-2 py-2 text-gray-600">{row.org.mjName ?? '-'}</td>
                    <td className="px-2 py-2 text-gray-600">{row.org.lawyerName ?? '-'}</td>
                    <td className="px-2 py-2 text-right tabular-nums">
                      {row.org.reviewDone.toLocaleString()} / {row.org.reviewTotal.toLocaleString()}
                    </td>
                    <td className="px-2 py-2 text-right tabular-nums">
                      {row.org.processDone.toLocaleString()} / {row.org.processTotal.toLocaleString()}
                    </td>
                    <td className="px-2 py-2 text-right text-gray-600 tabular-nums">
                      {row.lastContactedOn ?? '-'}
                      {row.contactCount > 0 && (
                        <span className="ml-1 text-xs text-gray-400">({row.contactCount})</span>
                      )}
                    </td>
                    <td className="px-2 py-2 text-right tabular-nums">{row.reportCount}</td>
                    <td className="px-2 py-2 text-right">
                      <button
                        type="button"
                        onClick={() => void openPanel(row)}
                        className="rounded-md border border-gray-300 px-2 py-0.5 text-xs text-gray-600 hover:bg-gray-50"
                      >
                        연락·보고서
                      </button>
                    </td>
                  </tr>
                ))
              )}
            </tbody>
          </table>
        </div>
      </section>

      {selected && (
        <div
          role="dialog"
          aria-label={`${selected.org.orgName} 연락·보고서`}
          className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-black/40 p-6"
        >
          <div className="w-full max-w-3xl rounded-lg bg-white shadow-xl">
            <div className="flex items-start justify-between gap-3 border-b border-gray-200 px-5 py-4">
              <div>
                <h2 className="text-base font-semibold">
                  {selected.org.orgNo} {selected.org.orgName}
                </h2>
                <p className="mt-1 text-xs text-gray-500">신청 확인 연락 이력과 최종 보고서</p>
              </div>
              <button
                type="button"
                aria-label="닫기"
                onClick={() => setSelected(null)}
                className="shrink-0 rounded-md border border-gray-300 px-2 py-1 text-xs text-gray-600 hover:bg-gray-50"
              >
                닫기
              </button>
            </div>

            <div className="space-y-6 px-5 py-4">
              {panelError && (
                <p className="rounded-md bg-red-50 px-3 py-2 text-sm text-red-700">{panelError}</p>
              )}

              <section>
                <h3 className="flex items-center gap-1.5 text-sm font-semibold">
                  신청 확인 연락 이력
                  <HelpButton topic="projects.contactLog" />
                </h3>

                <div className="mt-2 flex flex-wrap items-end gap-2">
                  <label className="flex flex-col gap-1 text-xs text-gray-500">
                    연락일
                    <input
                      type="date"
                      aria-label="연락일"
                      value={logDate}
                      onChange={(e) => setLogDate(e.target.value)}
                      className="rounded-md border border-gray-300 px-2 py-1.5 text-sm"
                    />
                  </label>
                  <label className="flex flex-col gap-1 text-xs text-gray-500">
                    방법
                    <select
                      aria-label="연락 방법"
                      value={logMethod}
                      onChange={(e) => setLogMethod(e.target.value)}
                      className="rounded-md border border-gray-300 px-2 py-1.5 text-sm"
                    >
                      {METHODS.map((m) => (
                        <option key={m} value={m}>{m}</option>
                      ))}
                    </select>
                  </label>
                  <label className="flex min-w-64 flex-1 flex-col gap-1 text-xs text-gray-500">
                    내용
                    <input
                      type="text"
                      aria-label="연락 내용"
                      value={logSummary}
                      onChange={(e) => setLogSummary(e.target.value)}
                      className="rounded-md border border-gray-300 px-2 py-1.5 text-sm"
                    />
                  </label>
                  <button
                    type="button"
                    disabled={panelBusy || logSummary.trim() === ''}
                    onClick={() => void submitLog()}
                    className="rounded-md bg-blue-600 px-3 py-1.5 text-sm text-white disabled:bg-gray-300"
                  >
                    {editingLogId ? '수정 저장' : '등록'}
                  </button>
                  {editingLogId && (
                    <button
                      type="button"
                      onClick={() => {
                        setEditingLogId(null)
                        setLogSummary('')
                      }}
                      className="rounded-md border border-gray-300 px-3 py-1.5 text-sm text-gray-600"
                    >
                      취소
                    </button>
                  )}
                </div>
                <p className="mt-1 text-xs text-gray-400">작성자는 로그인한 사용자로 자동 기록됩니다.</p>

                <ul className="mt-3 space-y-2">
                  {logs.length === 0 ? (
                    <li className="text-sm text-gray-400">등록된 연락 이력이 없습니다.</li>
                  ) : (
                    logs.map((log) => (
                      <li key={log.id} className="rounded-md border border-gray-200 p-2.5">
                        <div className="flex items-center justify-between gap-2">
                          <span className="text-xs text-gray-500">
                            {log.contactedOn} · {log.method} · {log.author}
                          </span>
                          <span className="flex gap-1">
                            <button
                              type="button"
                              onClick={() => {
                                setEditingLogId(log.id)
                                setLogDate(log.contactedOn)
                                setLogMethod(log.method)
                                setLogSummary(log.summary)
                              }}
                              className="rounded-md border border-gray-200 px-2 py-0.5 text-xs text-gray-500 hover:bg-gray-50"
                            >
                              수정
                            </button>
                            <button
                              type="button"
                              onClick={() => void removeLog(log)}
                              className="rounded-md border border-gray-200 px-2 py-0.5 text-xs text-gray-500 hover:bg-gray-50"
                            >
                              삭제
                            </button>
                          </span>
                        </div>
                        <p className="mt-1 whitespace-pre-wrap text-sm text-gray-800">{log.summary}</p>
                      </li>
                    ))
                  )}
                </ul>
              </section>

              <section>
                <h3 className="flex items-center gap-1.5 text-sm font-semibold">
                  최종 보고서
                  <HelpButton topic="projects.report" />
                </h3>

                <label className="mt-2 inline-flex cursor-pointer items-center gap-2 rounded-md border border-gray-300 px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-50">
                  보고서 업로드
                  <input
                    type="file"
                    aria-label="보고서 파일"
                    className="hidden"
                    onChange={(e) => {
                      const file = e.target.files?.[0]
                      if (file) {
                        void handleReportUpload(file)
                      }
                      e.target.value = ''
                    }}
                  />
                </label>

                <ul className="mt-3 space-y-2">
                  {reports.length === 0 ? (
                    <li className="text-sm text-gray-400">업로드된 보고서가 없습니다.</li>
                  ) : (
                    reports.map((report) => (
                      <li
                        key={report.id}
                        className="flex items-center justify-between gap-2 rounded-md border border-gray-200 p-2.5"
                      >
                        <div className="min-w-0">
                          <a
                            href={reportDownloadUrl(report.orgId, report.id)}
                            className="block truncate text-sm text-blue-700 hover:underline"
                          >
                            {report.fileName}
                          </a>
                          <span className="text-xs text-gray-400">
                            {formatSize(report.byteSize)} · {report.uploadedBy} ·{' '}
                            {formatDateTime(report.uploadedAt)}
                          </span>
                        </div>
                        <button
                          type="button"
                          onClick={() => void removeReport(report)}
                          className="shrink-0 rounded-md border border-gray-200 px-2 py-0.5 text-xs text-gray-500 hover:bg-gray-50"
                        >
                          삭제
                        </button>
                      </li>
                    ))
                  )}
                </ul>
              </section>
            </div>
          </div>
        </div>
      )}
    </div>
  )
}
