import { useState, useEffect, useCallback, useRef } from 'react';
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { saveReport } from '../services/reportsApi';
import {
  fetchSensitiveResourcesGeojson,
  fetchPredictionParticlesGeojson,
  fetchSensitivityEvaluationGeojson,
} from '@tabs/prediction/services/predictionApi';

// ─── Data Types ─────────────────────────────────────────────
export type ReportType = '초기보고서' | '지휘부 보고' | '예측보고서' | '종합보고서' | '유출유 보고';
export type ReportStatus = '완료' | '수행중' | '테스트';
export type Jurisdiction = '남해청' | '서해청' | '중부청' | '동해청' | '제주청';
export type AnalysisCategory = '유출유 확산예측' | 'HNS 대기확산' | '긴급구난' | '';

export interface OilSpillReportData {
  id: string;
  title: string;
  createdAt: string;
  updatedAt: string;
  author: string;
  reportType: ReportType;
  analysisCategory: AnalysisCategory;
  jurisdiction: Jurisdiction;
  status: ReportStatus;
  incident: {
    name: string;
    writeTime: string;
    shipName: string;
    agent: string;
    location: string;
    lat: string;
    lon: string;
    occurTime: string;
    accidentType: string;
    pollutant: string;
    spillAmount: string;
    depth: string;
    seabed: string;
  };
  tide: {
    date: string;
    tideType: string;
    lowTide1: string;
    highTide1: string;
    lowTide2: string;
    highTide2: string;
  }[];
  weather: {
    time: string;
    sunrise: string;
    sunset: string;
    windDir: string;
    windSpeed: string;
    currentDir: string;
    currentSpeed: string;
    waveHeight: string;
  }[];
  spread: {
    elapsed: string;
    weathered: string;
    seaRemain: string;
    coastAttach: string;
    area: string;
  }[];
  analysis: string;
  aquaculture: { type: string; area: string; distance: string }[];
  beaches: { name: string; distance: string }[];
  markets: { name: string; distance: string }[];
  esi: { code: string; type: string; length: string }[];
  species: { category: string; species: string }[];
  habitat: { type: string; area: string }[];
  sensitivity: { level: string; area: string; color: string }[];
  vessels: {
    name: string;
    org: string;
    dist: string;
    speed: string;
    ton: string;
    collectorType: string;
    collectorCap: string;
    boomType: string;
    boomLength: string;
  }[];
  etcEquipment: string;
  recovery: { shipName: string; period: string }[];
  result: {
    spillTotal: string;
    weatheredTotal: string;
    recoveredTotal: string;
    seaRemainTotal: string;
    coastAttachTotal: string;
  };
  capturedMapImage?: string;
  step3MapImage?: string;
  step6MapImage?: string;
  hasMapCapture?: boolean;
  acdntSn?: number;
  sensitiveMapImage?: string;
  sensitivityMapImage?: string;
}

// eslint-disable-next-line react-refresh/only-export-components
export function createEmptyReport(jurisdiction?: Jurisdiction): OilSpillReportData {
  const now = new Date();
  const ts = `${now.getFullYear()}.${String(now.getMonth() + 1).padStart(2, '0')}.${String(now.getDate()).padStart(2, '0')}  ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
  return {
    id: `RPT-${Date.now()}`,
    title: '',
    createdAt: now.toISOString(),
    updatedAt: now.toISOString(),
    author: '',
    reportType: '예측보고서',
    analysisCategory: '',
    jurisdiction: jurisdiction || '',
    status: '수행중',
    incident: {
      name: '',
      writeTime: ts,
      shipName: '',
      agent: '',
      location: '',
      lat: '',
      lon: '',
      occurTime: '',
      accidentType: '',
      pollutant: '',
      spillAmount: '',
      depth: '',
      seabed: '',
    },
    tide: [{ date: '', tideType: '', lowTide1: '', highTide1: '', lowTide2: '', highTide2: '' }],
    weather: [
      {
        time: '',
        sunrise: '',
        sunset: '',
        windDir: '',
        windSpeed: '',
        currentDir: '',
        currentSpeed: '',
        waveHeight: '',
      },
    ],
    spread: [
      { elapsed: '3시간', weathered: '', seaRemain: '', coastAttach: '', area: '' },
      { elapsed: '6시간', weathered: '', seaRemain: '', coastAttach: '', area: '' },
    ],
    analysis: '',
    aquaculture: [{ type: '', area: '', distance: '' }],
    beaches: [{ name: '', distance: '' }],
    markets: [{ name: '', distance: '' }],
    esi: [
      { code: 'ESI 1', type: '수직암반', length: '' },
      { code: 'ESI 2', type: '수평암반', length: '' },
      { code: 'ESI 3', type: '세립질 모래', length: '' },
      { code: 'ESI 4', type: '조립질 모래', length: '' },
      { code: 'ESI 5', type: '모래·자갈', length: '' },
      { code: 'ESI 6A', type: '자갈', length: '' },
      { code: 'ESI 6B', type: '투과성 사석', length: '' },
      { code: 'ESI 7', type: '반폐쇄성 해안', length: '' },
      { code: 'ESI 8A', type: '갯벌', length: '' },
      { code: 'ESI 8B', type: '염습지', length: '' },
    ],
    species: [
      { category: '양서파충류', species: '' },
      { category: '조류', species: '' },
      { category: '포유류', species: '' },
    ],
    habitat: [{ type: '갯벌', area: '' }],
    sensitivity: [
      { level: '매우 높음', area: '', color: '#ef4444' },
      { level: '높음', area: '', color: '#f97316' },
      { level: '보통', area: '', color: '#eab308' },
      { level: '낮음', area: '', color: '#22c55e' },
    ],
    vessels: [
      {
        name: '',
        org: '',
        dist: '',
        speed: '',
        ton: '',
        collectorType: '',
        collectorCap: '',
        boomType: '',
        boomLength: '',
      },
    ],
    etcEquipment: '',
    recovery: [{ shipName: '', period: '' }],
    result: {
      spillTotal: '',
      weatheredTotal: '',
      recoveredTotal: '',
      seaRemainTotal: '',
      coastAttachTotal: '',
    },
  };
}

// eslint-disable-next-line react-refresh/only-export-components
export function createSampleReport(): OilSpillReportData {
  return {
    id: `RPT-${Date.now()}`,
    title: '여수 수변공원 Diesel 유출사고 대응지원',
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    author: '남해청_방제과',
    reportType: '초기보고서',
    analysisCategory: '유출유 확산예측',
    jurisdiction: '남해청',
    status: '완료',
    incident: {
      name: '여수 수변공원 유출사고',
      writeTime: '2025.07.16  13:48',
      shipName: '수변공원',
      agent: '',
      location: '여수 돌산 남방',
      lat: '34° 43′ 37.6″',
      lon: '127° 43′ 32.6″',
      occurTime: '2025. 07. 08. 17:55',
      accidentType: '시설 파손',
      pollutant: 'Diesel',
      spillAmount: '1㎘',
      depth: '12m',
      seabed: '모래',
    },
    tide: [
      {
        date: '2025-07-08 20:55',
        tideType: '배꼽사리',
        lowTide1: '01:53 (146)',
        highTide1: '13:19 (104)',
        lowTide2: '07:17 (253)',
        highTide2: '20:24 (310)',
      },
      {
        date: '2025-07-08 23:55',
        tideType: '배꼽사리',
        lowTide1: '01:53 (146)',
        highTide1: '13:19 (104)',
        lowTide2: '07:17 (253)',
        highTide2: '20:24 (310)',
      },
    ],
    weather: [
      {
        time: '2025-07-08 20:55',
        sunrise: '05:22',
        sunset: '19:46',
        windDir: '북동',
        windSpeed: '0.0',
        currentDir: '북',
        currentSpeed: '0.0 / 0.0',
        waveHeight: '0.0',
      },
      {
        time: '2025-07-08 23:55',
        sunrise: '05:22',
        sunset: '19:46',
        windDir: '북동',
        windSpeed: '0.0',
        currentDir: '북',
        currentSpeed: '0.0 / 0.0',
        waveHeight: '0.0',
      },
    ],
    spread: [
      { elapsed: '3시간', weathered: '0.48', seaRemain: '0.52', coastAttach: '0.12', area: '1.75' },
      { elapsed: '6시간', weathered: '0.64', seaRemain: '0.36', coastAttach: '0.24', area: '3.49' },
    ],
    analysis: '',
    aquaculture: [
      { type: '', area: '3.19', distance: '0.56' },
      { type: '', area: '20.15', distance: '0.83' },
      { type: '어류', area: '3.84', distance: '1.14' },
      { type: '', area: '2.89', distance: '1.40' },
      { type: '어류', area: '0.90', distance: '1.42' },
    ],
    beaches: [
      { name: '검은모래해수욕장', distance: '5.86' },
      { name: '무슬목해수욕장', distance: '6.69' },
      { name: '모사금해수욕장', distance: '8.18' },
    ],
    markets: [{ name: '돌산대교 회타운', distance: '1.09' }],
    esi: [
      { code: 'ESI 1', type: '수직암반', length: '29.05 km' },
      { code: 'ESI 2', type: '수평암반', length: '13.76 km' },
      { code: 'ESI 3', type: '세립질 모래', length: '1.03 km' },
      { code: 'ESI 4', type: '조립질 모래', length: '0.47 km' },
      { code: 'ESI 5', type: '모래·자갈', length: '21.10 km' },
      { code: 'ESI 6A', type: '자갈', length: '15.29 km' },
      { code: 'ESI 6B', type: '투과성 사석', length: '26.60 km' },
      { code: 'ESI 7', type: '반폐쇄성 해안', length: '9.39 km' },
      { code: 'ESI 8A', type: '갯벌', length: '0.00 km' },
      { code: 'ESI 8B', type: '염습지', length: '3.43 km' },
    ],
    species: [
      { category: '양서파충류', species: '' },
      { category: '조류', species: '뿔논병아리(겨울철새), 꾀꼬리(여름철새)' },
      { category: '포유류', species: '수달' },
    ],
    habitat: [{ type: '갯벌', area: '4.32 km²' }],
    sensitivity: [
      { level: '매우 높음', area: '18.54', color: '#ef4444' },
      { level: '높음', area: '31.32', color: '#f97316' },
      { level: '보통', area: '59.22', color: '#eab308' },
      { level: '낮음', area: '32.13', color: '#22c55e' },
    ],
    vessels: [
      {
        name: '방제15호',
        org: '서해청',
        dist: '0.41',
        speed: '7.0',
        ton: '450.0',
        collectorType: '흡착',
        collectorCap: '140.0',
        boomType: 'B',
        boomLength: '60',
      },
      {
        name: '방제26호',
        org: '서해청',
        dist: '0.41',
        speed: '13.0',
        ton: '360.0',
        collectorType: '흡착',
        collectorCap: '100.0',
        boomType: 'B',
        boomLength: '300',
      },
      {
        name: '방제1001호',
        org: '서해청',
        dist: '0.74',
        speed: '10.0',
        ton: '564.0',
        collectorType: '흡착',
        collectorCap: '30.0',
        boomType: 'B',
        boomLength: '20',
      },
      {
        name: '전남939호',
        org: '서해청',
        dist: '0.74',
        speed: '10.0',
        ton: '149.0',
        collectorType: '흡착',
        collectorCap: '30.0',
        boomType: 'B',
        boomLength: '300',
      },
      {
        name: '동양방제호',
        org: '서해청',
        dist: '1.78',
        speed: '10.0',
        ton: '179.0',
        collectorType: '위어,흡착',
        collectorCap: '66.0',
        boomType: 'C',
        boomLength: '300',
      },
      {
        name: '화학방제2함',
        org: '서해청',
        dist: '3.00',
        speed: '13.0',
        ton: '501.0',
        collectorType: '위어,브러쉬',
        collectorCap: '150.0',
        boomType: '특수',
        boomLength: '60',
      },
      {
        name: '우진방제호',
        org: '서해청',
        dist: '13.22',
        speed: '9.0',
        ton: '79.0',
        collectorType: '위어',
        collectorCap: '20.0',
        boomType: 'C',
        boomLength: '300',
      },
    ],
    etcEquipment: '',
    recovery: [{ shipName: '방제15호', period: '0' }],
    result: {
      spillTotal: '1',
      weatheredTotal: '0.64',
      recoveredTotal: '0',
      seaRemainTotal: '0.36',
      coastAttachTotal: '0.24',
    },
  };
}

// ─── localStorage helpers 제거됨 — reportsApi.ts 사용 ────────

// ─── Styles ─────────────────────────────────────────────────
const S = {
  page: {
    background: 'var(--bg-surface)',
    padding: '32px 40px',
    marginBottom: '24px',
    borderRadius: '6px',
    border: '1px solid var(--stroke-default)',
    fontFamily: 'var(--font-korean)',
    fontSize: 'var(--font-size-label-1)',
    lineHeight: '1.6',
    position: 'relative' as const,
    width: '100%',
    boxSizing: 'border-box' as const,
  },
  sectionTitle: {
    background: 'rgba(6,182,212,0.12)',
    color: 'var(--color-accent)',
    padding: '8px 16px',
    fontSize: 'var(--font-size-title-4)',
    fontWeight: 700,
    marginBottom: '12px',
    borderRadius: '4px',
    border: '1px solid rgba(6,182,212,0.2)',
  },
  subHeader: {
    fontSize: 'var(--font-size-title-3)',
    fontWeight: 700,
    color: 'var(--color-accent)',
    marginBottom: '12px',
    borderBottom: '2px solid var(--stroke-default)',
    paddingBottom: '6px',
  },
  table: {
    width: '100%',
    tableLayout: 'fixed' as const,
    borderCollapse: 'collapse' as const,
    fontSize: 'var(--font-size-caption)',
    marginBottom: '16px',
  },
  th: {
    background: 'var(--bg-card)',
    border: '1px solid var(--stroke-default)',
    padding: '6px 10px',
    fontWeight: 600,
    color: 'var(--fg-sub)',
    textAlign: 'center' as const,
    fontSize: 'var(--font-size-caption)',
  },
  td: {
    border: '1px solid var(--stroke-default)',
    padding: '5px 10px',
    textAlign: 'center' as const,
    fontSize: 'var(--font-size-caption)',
    color: 'var(--fg-sub)',
  },
  tdLeft: {
    border: '1px solid var(--stroke-default)',
    padding: '5px 10px',
    textAlign: 'left' as const,
    fontSize: 'var(--font-size-caption)',
    color: 'var(--fg-sub)',
  },
  thLabel: {
    background: 'var(--bg-card)',
    border: '1px solid var(--stroke-default)',
    padding: '6px 10px',
    fontWeight: 600,
    color: 'var(--fg-sub)',
    textAlign: 'left' as const,
    fontSize: 'var(--font-size-caption)',
    width: '120px',
  },
  mapPlaceholder: {
    width: '100%',
    height: '240px',
    background: 'var(--bg-base)',
    border: '2px dashed var(--stroke-default)',
    borderRadius: '4px',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    color: 'var(--fg-disabled)',
    fontSize: 'var(--font-size-title-4)',
    fontWeight: 600,
    marginBottom: '16px',
  },
};

// ─── Editable cell ──────────────────────────────────────────
const inputStyle: React.CSSProperties = {
  width: '100%',
  background: 'var(--bg-base)',
  border: '1px solid var(--stroke-light)',
  borderRadius: '3px',
  padding: '4px 8px',
  fontSize: 'var(--font-size-caption)',
  outline: 'none',
  textAlign: 'center',
};

function ECell({
  value,
  editing,
  onChange,
  align,
  placeholder,
}: {
  value: string;
  editing: boolean;
  onChange?: (v: string) => void;
  align?: 'left' | 'center';
  placeholder?: string;
}) {
  const style = align === 'left' ? S.tdLeft : S.td;
  if (!editing) {
    return (
      <td
        style={{
          ...style,
          color: value ? 'var(--fg-default)' : 'var(--fg-disabled)',
          fontStyle: value ? 'normal' : 'italic',
        }}
      >
        {value || placeholder || '-'}
      </td>
    );
  }
  return (
    <td style={style}>
      <input
        style={{ ...inputStyle, textAlign: align || 'center' }}
        value={value}
        onChange={(e) => onChange?.(e.target.value)}
        placeholder={placeholder}
      />
    </td>
  );
}

function AddRowBtn({ onClick, label }: { onClick: () => void; label?: string }) {
  return (
    <button
      onClick={onClick}
      className="px-3 py-1 text-label-2 font-semibold text-color-accent bg-[rgba(6,182,212,0.08)] border border-dashed border-color-accent rounded-sm cursor-pointer mb-3"
    >
      + {label || '행 추가'}
    </button>
  );
}

// ─── Page components ────────────────────────────────────────
function Page1({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const inc = data.incident;
  const set = (k: keyof typeof inc, v: string) =>
    onChange({ ...data, incident: { ...inc, [k]: v } });

  return (
    <div style={S.page}>
      <div className="absolute top-2.5 right-4 text-caption text-fg-disabled font-semibold">
        해양오염방제지원시스템
      </div>
      <div
        className="text-color-accent text-title-1 font-bold mb-5 rounded px-5 py-3 text-center tracking-wide border"
        style={{ background: 'rgba(6,182,212,0.1)', border: '1px solid rgba(6,182,212,0.2)' }}
      >
        유류오염사고 대응지원 상황도
      </div>
      <div style={S.sectionTitle}>1. 사고 정보</div>
      <table style={S.table}>
        <colgroup>
          <col style={{ width: '14%' }} />
          <col style={{ width: '36%' }} />
          <col style={{ width: '14%' }} />
          <col style={{ width: '36%' }} />
        </colgroup>
        <tbody>
          <tr>
            <td style={S.thLabel}>사고명</td>
            <ECell
              value={inc.name}
              editing={editing}
              onChange={(v) => set('name', v)}
              placeholder="사고명 입력"
            />
            <td style={S.thLabel}>작성시간</td>
            <ECell value={inc.writeTime} editing={editing} onChange={(v) => set('writeTime', v)} />
          </tr>
          <tr>
            <td style={S.thLabel}>선명(시설명)</td>
            <ECell
              value={inc.shipName}
              editing={editing}
              onChange={(v) => set('shipName', v)}
              placeholder="선명"
            />
            <td style={S.thLabel}>제원</td>
            <ECell
              value={inc.agent}
              editing={editing}
              onChange={(v) => set('agent', v)}
              placeholder="제원"
            />
          </tr>
          <tr>
            <td style={S.thLabel}>사고위치</td>
            <ECell
              value={inc.location}
              editing={editing}
              onChange={(v) => set('location', v)}
              placeholder="위치"
            />
            <td style={S.thLabel}>좌표</td>
            <ECell value={`위도: ${inc.lat}  경도: ${inc.lon}`} editing={false} />
          </tr>
          {editing && (
            <tr>
              <td style={S.thLabel}>위도</td>
              <ECell
                value={inc.lat}
                editing
                onChange={(v) => set('lat', v)}
                placeholder="34° 43′ 37.6″"
              />
              <td style={S.thLabel}>경도</td>
              <ECell
                value={inc.lon}
                editing
                onChange={(v) => set('lon', v)}
                placeholder="127° 43′ 32.6″"
              />
            </tr>
          )}
          <tr>
            <td style={S.thLabel}>발생시각</td>
            <ECell value={inc.occurTime} editing={editing} onChange={(v) => set('occurTime', v)} />
            <td style={S.thLabel}>사고유형</td>
            <ECell
              value={inc.accidentType}
              editing={editing}
              onChange={(v) => set('accidentType', v)}
              placeholder="사고유형"
            />
          </tr>
          <tr>
            <td style={S.thLabel}>오염물질</td>
            <ECell value={inc.pollutant} editing={editing} onChange={(v) => set('pollutant', v)} />
            <td style={S.thLabel}>유출 추정량</td>
            <ECell
              value={inc.spillAmount}
              editing={editing}
              onChange={(v) => set('spillAmount', v)}
            />
          </tr>
          <tr>
            <td style={S.thLabel}>수심</td>
            <ECell
              value={inc.depth}
              editing={editing}
              onChange={(v) => set('depth', v)}
              placeholder="수심"
            />
            <td style={S.thLabel}>저질</td>
            <ECell
              value={inc.seabed}
              editing={editing}
              onChange={(v) => set('seabed', v)}
              placeholder="저질"
            />
          </tr>
        </tbody>
      </table>
    </div>
  );
}

function Page2({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const setTide = (i: number, k: string, v: string) => {
    const t = [...data.tide];
    t[i] = { ...t[i], [k]: v };
    onChange({ ...data, tide: t });
  };
  const setWeather = (i: number, k: string, v: string) => {
    const w = [...data.weather];
    w[i] = { ...w[i], [k]: v };
    onChange({ ...data, weather: w });
  };
  const setSpread = (i: number, k: string, v: string) => {
    const s = [...data.spread];
    s[i] = { ...s[i], [k]: v };
    onChange({ ...data, spread: s });
  };

  return (
    <div style={S.page}>
      <div className="absolute top-2.5 right-4 text-caption text-fg-disabled font-semibold">
        해양오염방제지원시스템
      </div>
      <div style={S.sectionTitle}>2. 해양기상정보</div>
      <div style={S.subHeader}>조석 정보</div>
      <table style={S.table}>
        <thead>
          <tr>
            <th style={S.th}>일자</th>
            <th style={S.th}>물때</th>
            <th style={S.th} colSpan={2}>
              저조
            </th>
            <th style={S.th} colSpan={2}>
              고조
            </th>
          </tr>
        </thead>
        <tbody>
          {data.tide.map((t, i) => (
            <tr key={i}>
              <ECell value={t.date} editing={editing} onChange={(v) => setTide(i, 'date', v)} />
              <ECell
                value={t.tideType}
                editing={editing}
                onChange={(v) => setTide(i, 'tideType', v)}
              />
              <ECell
                value={t.lowTide1}
                editing={editing}
                onChange={(v) => setTide(i, 'lowTide1', v)}
              />
              <ECell
                value={t.lowTide2}
                editing={editing}
                onChange={(v) => setTide(i, 'lowTide2', v)}
              />
              <ECell
                value={t.highTide1}
                editing={editing}
                onChange={(v) => setTide(i, 'highTide1', v)}
              />
              <ECell
                value={t.highTide2}
                editing={editing}
                onChange={(v) => setTide(i, 'highTide2', v)}
              />
            </tr>
          ))}
        </tbody>
      </table>
      {editing && (
        <AddRowBtn
          onClick={() =>
            onChange({
              ...data,
              tide: [
                ...data.tide,
                {
                  date: '',
                  tideType: '',
                  lowTide1: '',
                  highTide1: '',
                  lowTide2: '',
                  highTide2: '',
                },
              ],
            })
          }
        />
      )}

      <div style={S.subHeader}>기상 정보</div>
      <table style={S.table}>
        <thead>
          <tr>
            <th style={S.th}>기상 예측시간</th>
            <th style={S.th}>일출</th>
            <th style={S.th}>일몰</th>
            <th style={S.th}>풍향</th>
            <th style={S.th}>풍속(m/s)</th>
            <th style={S.th}>유향</th>
            <th style={S.th}>유속(knot/m/s)</th>
            <th style={S.th}>파고(m)</th>
          </tr>
        </thead>
        <tbody>
          {data.weather.map((w, i) => (
            <tr key={i}>
              <ECell value={w.time} editing={editing} onChange={(v) => setWeather(i, 'time', v)} />
              <ECell
                value={w.sunrise}
                editing={editing}
                onChange={(v) => setWeather(i, 'sunrise', v)}
              />
              <ECell
                value={w.sunset}
                editing={editing}
                onChange={(v) => setWeather(i, 'sunset', v)}
              />
              <ECell
                value={w.windDir}
                editing={editing}
                onChange={(v) => setWeather(i, 'windDir', v)}
              />
              <ECell
                value={w.windSpeed}
                editing={editing}
                onChange={(v) => setWeather(i, 'windSpeed', v)}
              />
              <ECell
                value={w.currentDir}
                editing={editing}
                onChange={(v) => setWeather(i, 'currentDir', v)}
              />
              <ECell
                value={w.currentSpeed}
                editing={editing}
                onChange={(v) => setWeather(i, 'currentSpeed', v)}
              />
              <ECell
                value={w.waveHeight}
                editing={editing}
                onChange={(v) => setWeather(i, 'waveHeight', v)}
              />
            </tr>
          ))}
        </tbody>
      </table>
      {editing && (
        <AddRowBtn
          onClick={() =>
            onChange({
              ...data,
              weather: [
                ...data.weather,
                {
                  time: '',
                  sunrise: '',
                  sunset: '',
                  windDir: '',
                  windSpeed: '',
                  currentDir: '',
                  currentSpeed: '',
                  waveHeight: '',
                },
              ],
            })
          }
        />
      )}

      <div style={S.sectionTitle}>3. 유출유 확산예측</div>
      <div className="flex gap-4 mb-4">
        <div style={{ flex: 1, minWidth: 0 }}>
          {data.step3MapImage ? (
            <img
              src={data.step3MapImage}
              alt="확산예측 3시간 지도"
              style={{
                width: '100%',
                height: 'auto',
                display: 'block',
                borderRadius: '4px',
                border: '1px solid var(--stroke-default)',
              }}
            />
          ) : (
            <div style={S.mapPlaceholder}>확산예측 3시간 지도</div>
          )}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          {data.step6MapImage ? (
            <img
              src={data.step6MapImage}
              alt="확산예측 6시간 지도"
              style={{
                width: '100%',
                height: 'auto',
                display: 'block',
                borderRadius: '4px',
                border: '1px solid var(--stroke-default)',
              }}
            />
          ) : (
            <div style={S.mapPlaceholder}>확산예측 6시간 지도</div>
          )}
        </div>
      </div>
      <div style={S.subHeader}>시간별 상세정보</div>
      <table style={S.table}>
        <thead>
          <tr>
            <th style={S.th}>경과시간</th>
            <th style={S.th}>풍화량(kl)</th>
            <th style={S.th}>해상잔존량(kl)</th>
            <th style={S.th}>연안부착량(kl)</th>
            <th style={S.th}>오염해역면적(km²)</th>
          </tr>
        </thead>
        <tbody>
          {data.spread.map((s, i) => (
            <tr key={i}>
              <ECell
                value={s.elapsed}
                editing={editing}
                onChange={(v) => setSpread(i, 'elapsed', v)}
              />
              <ECell
                value={s.weathered}
                editing={editing}
                onChange={(v) => setSpread(i, 'weathered', v)}
              />
              <ECell
                value={s.seaRemain}
                editing={editing}
                onChange={(v) => setSpread(i, 'seaRemain', v)}
              />
              <ECell
                value={s.coastAttach}
                editing={editing}
                onChange={(v) => setSpread(i, 'coastAttach', v)}
              />
              <ECell value={s.area} editing={editing} onChange={(v) => setSpread(i, 'area', v)} />
            </tr>
          ))}
        </tbody>
      </table>
      {editing && (
        <AddRowBtn
          onClick={() =>
            onChange({
              ...data,
              spread: [
                ...data.spread,
                { elapsed: '', weathered: '', seaRemain: '', coastAttach: '', area: '' },
              ],
            })
          }
        />
      )}
    </div>
  );
}

function Page3({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  return (
    <div style={S.page}>
      <div className="absolute top-2.5 right-4 text-caption text-fg-disabled font-semibold">
        해양오염방제지원시스템
      </div>
      <div style={S.sectionTitle}>분석</div>
      {editing ? (
        <textarea
          value={data.analysis}
          onChange={(e) => onChange({ ...data, analysis: e.target.value })}
          placeholder="분석 내용을 작성하세요..."
          style={{
            width: '100%',
            minHeight: '300px',
            background: 'var(--bg-base)',
            border: '1px solid var(--stroke-light)',
            borderRadius: '4px',
            padding: '16px',
            fontSize: 'var(--font-size-title-4)',
            outline: 'none',
            resize: 'vertical',
            lineHeight: '1.8',
          }}
        />
      ) : (
        <div
          style={{
            minHeight: '300px',
            border: data.analysis
              ? '1px solid var(--stroke-default)'
              : '2px dashed var(--stroke-default)',
            borderRadius: '4px',
            padding: '16px',
            color: data.analysis ? 'var(--fg-default)' : 'var(--fg-disabled)',
            fontStyle: data.analysis ? 'normal' : 'italic',
            fontSize: 'var(--font-size-title-4)',
            whiteSpace: 'pre-wrap',
            lineHeight: '1.8',
          }}
        >
          {data.analysis || '분석 내용이 없습니다'}
        </div>
      )}
    </div>
  );
}

const getSeasonKey = (occurTime: string): 'SP_G' | 'SM_G' | 'FA_G' | 'WT_G' => {
  const m = occurTime.match(/\d{4}[.\-\s]+(\d{1,2})[.\-\s]/);
  const month = m ? parseInt(m[1]) : 0;
  if (month >= 3 && month <= 5) return 'SP_G';
  if (month >= 6 && month <= 8) return 'SM_G';
  if (month >= 9 && month <= 11) return 'FA_G';
  return 'WT_G';
};

const parseCoord = (s: string): number | null => {
  const d = parseFloat(s);
  if (!isNaN(d)) return d;
  const m = s.match(/(\d+)[°]\s*(\d+)[′']\s*([\d.]+)[″"]/);
  if (m) return Number(m[1]) + Number(m[2]) / 60 + Number(m[3]) / 3600;
  return null;
};

const haversineKm = (lat1: number, lon1: number, lat2: number, lon2: number): number => {
  const R = 6371;
  const dLat = ((lat2 - lat1) * Math.PI) / 180;
  const dLon = ((lon2 - lon1) * Math.PI) / 180;
  const a =
    Math.sin(dLat / 2) ** 2 +
    Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) * Math.sin(dLon / 2) ** 2;
  return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
};

const getGeomCentroid = (geom: { type: string; coordinates: unknown }): [number, number] | null => {
  if (geom.type === 'Point') return geom.coordinates as [number, number];
  if (geom.type === 'Polygon') {
    const pts = (geom.coordinates as [number, number][][])[0];
    const avg = pts.reduce((a, c) => [a[0] + c[0], a[1] + c[1]], [0, 0]);
    return [avg[0] / pts.length, avg[1] / pts.length];
  }
  if (geom.type === 'MultiPolygon') {
    const all = (geom.coordinates as [number, number][][][]).flatMap((p) => p[0]);
    const avg = all.reduce((a, c) => [a[0] + c[0], a[1] + c[1]], [0, 0]);
    return [avg[0] / all.length, avg[1] / all.length];
  }
  return null;
};

const CATEGORY_COLORS = [
  { keywords: ['어장', '양식'], color: '#f97316', label: '어장/양식장' },
  { keywords: ['해수욕'], color: '#3b82f6', label: '해수욕장' },
  { keywords: ['수산시장', '어시장'], color: '#a855f7', label: '수산시장' },
  { keywords: ['갯벌'], color: '#92400e', label: '갯벌' },
  { keywords: ['서식지'], color: '#16a34a', label: '서식지' },
  {
    keywords: ['보호종', '생물', '조류', '포유', '파충', '양서'],
    color: '#ec4899',
    label: '보호종/생물종',
  },
] as const;

const getCategoryColor = (category: string): string => {
  for (const { keywords, color } of CATEGORY_COLORS) {
    if ((keywords as readonly string[]).some((kw) => category.includes(kw))) return color;
  }
  return '#06b6d4';
};

function SensitiveResourceMapSection({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const mapContainerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<maplibregl.Map | null>(null);
  const [mapVisible, setMapVisible] = useState(false);
  const [loading, setLoading] = useState(false);
  const [capturing, setCapturing] = useState(false);
  const [legendLabels, setLegendLabels] = useState<string[]>([]);
  const acdntSn = data.acdntSn;

  const RELEVANT_KEYWORDS = [
    '양식',
    '어장',
    '해수욕',
    '수산시장',
    '어시장',
    '갯벌',
    '서식지',
    '보호종',
    '생물',
    '조류',
    '포유',
    '파충',
  ];

  const handleLoad = async () => {
    if (!acdntSn) return;
    setLoading(true);
    try {
      const [geojson, particlesGeojson] = await Promise.all([
        fetchSensitiveResourcesGeojson(acdntSn),
        fetchPredictionParticlesGeojson(acdntSn),
      ]);
      // 관련 카테고리만 필터링 + 카테고리별 색상 추가
      const filteredGeojson = {
        ...geojson,
        features: geojson.features
          .filter((f) => {
            const cat = (f.properties as { category?: string })?.category ?? '';
            return RELEVANT_KEYWORDS.some((kw) => cat.includes(kw));
          })
          .map((f) => ({
            ...f,
            properties: {
              ...f.properties,
              _color: getCategoryColor((f.properties as { category?: string })?.category ?? ''),
            },
          })),
      };
      // 실제 존재하는 카테고리 라벨만 범례에 표시
      const presentColors = new Set(
        filteredGeojson.features.map((f) => (f.properties as { _color: string })._color),
      );
      setLegendLabels(
        CATEGORY_COLORS.filter((c) => presentColors.has(c.color)).map((c) => c.label),
      );
      // 민감자원 GeoJSON → 6개 섹션 자동 채우기
      const HABITAT_TYPES = [
        '갯벌',
        '해조류서식지',
        '바다목장',
        '바다숲',
        '산호류서식지',
        '인공어초',
        '해초류서식지',
      ];
      const incLat = parseCoord(data.incident.lat);
      const incLon = parseCoord(data.incident.lon);
      const calcDist = (geom: { type: string; coordinates: unknown }) => {
        if (incLat == null || incLon == null) return '';
        const centroid = getGeomCentroid(geom);
        return centroid ? haversineKm(incLat, incLon, centroid[1], centroid[0]).toFixed(2) : '';
      };

      // aquaculture (어장)
      const aquacultureRows = geojson.features
        .filter((f) => ((f.properties as { category?: string })?.category ?? '').includes('어장'))
        .sort((a, b) => {
          const aNo = String((a.properties as Record<string, unknown>)['lcns_no'] ?? '');
          const bNo = String((b.properties as Record<string, unknown>)['lcns_no'] ?? '');
          return aNo.localeCompare(bNo, 'ko', { numeric: true });
        })
        .map((f) => {
          const p = f.properties as Record<string, unknown>;
          const lcnsNo = String(p['lcns_no'] ?? '');
          const fidsKnd = String(p['fids_knd'] ?? '');
          const farmKnd = String(p['farm_knd'] ?? '');
          const parts = [lcnsNo, fidsKnd, farmKnd].filter(Boolean);
          return {
            type: parts.join('_'),
            area: p['area'] != null ? Number(p['area']).toFixed(2) : '',
            distance: calcDist(f.geometry as { type: string; coordinates: unknown }),
          };
        });

      // beaches (해수욕장)
      const beachRows = geojson.features
        .filter((f) => ((f.properties as { category?: string })?.category ?? '').includes('해수욕'))
        .map((f) => {
          const p = f.properties as Record<string, unknown>;
          return {
            name: String(p['beach_nm'] ?? p['name'] ?? p['nm'] ?? ''),
            distance: calcDist(f.geometry as { type: string; coordinates: unknown }),
          };
        });

      // markets (수산시장·어시장)
      const marketRows = geojson.features
        .filter((f) => {
          const cat = (f.properties as { category?: string })?.category ?? '';
          return cat.includes('수산시장') || cat.includes('어시장');
        })
        .map((f) => {
          const p = f.properties as Record<string, unknown>;
          return {
            name: String(p['name'] ?? p['market_nm'] ?? p['nm'] ?? ''),
            distance: calcDist(f.geometry as { type: string; coordinates: unknown }),
          };
        });

      // esi (해안선) — 기존 10개 행의 length만 갱신
      const esiFeatures = geojson.features.filter((f) => {
        const cat = (f.properties as { category?: string })?.category ?? '';
        return cat.includes('해안선') || cat.includes('ESI');
      });
      const esiLengthMap: Record<string, string> = {};
      esiFeatures.forEach((f) => {
        const p = f.properties as Record<string, unknown>;
        const code = String(p['esi_cd'] ?? '');
        const len = p['length_km'] ?? p['len_km'];
        if (code && len != null) esiLengthMap[code] = `${Number(len).toFixed(2)} km`;
      });
      const esiRows =
        esiFeatures.length > 0
          ? data.esi.map((row) => ({
              ...row,
              length:
                esiLengthMap[row.code.replace('ESI ', '')] ?? esiLengthMap[row.code] ?? row.length,
            }))
          : data.esi;

      // species (보호종·생물종) — 3개 고정 행 유지, species 컬럼만 갱신
      const SPECIES_MAP: Record<string, string[]> = {
        양서파충류: ['파충', '양서'],
        조류: ['조류'],
        포유류: ['포유'],
      };
      const speciesCollected: Record<string, string[]> = { 양서파충류: [], 조류: [], 포유류: [] };
      geojson.features.forEach((f) => {
        const cat = (f.properties as { category?: string })?.category ?? '';
        const p = f.properties as Record<string, unknown>;
        const nm = String(p['name'] ?? p['species_nm'] ?? '');
        if (!nm) return;
        for (const [row, kws] of Object.entries(SPECIES_MAP)) {
          if (kws.some((kw) => cat.includes(kw))) {
            speciesCollected[row].push(nm);
            break;
          }
        }
      });
      const hasSpecies = Object.values(speciesCollected).some((arr) => arr.length > 0);
      const speciesRows = hasSpecies
        ? data.species.map((row) => ({
            ...row,
            species: speciesCollected[row.category]?.join(', ') ?? row.species,
          }))
        : data.species;

      // habitat (서식지) — 타입별 면적 합산
      const habitatFeatures = geojson.features.filter((f) =>
        HABITAT_TYPES.some((t) =>
          ((f.properties as { category?: string })?.category ?? '').includes(t),
        ),
      );
      const habitatMap: Record<string, number> = {};
      habitatFeatures.forEach((f) => {
        const cat = (f.properties as { category?: string })?.category ?? '';
        const p = f.properties as Record<string, unknown>;
        habitatMap[cat] = (habitatMap[cat] ?? 0) + (p['area'] != null ? Number(p['area']) : 0);
      });
      const habitatRows =
        habitatFeatures.length > 0
          ? Object.entries(habitatMap).map(([type, area]) => ({
              type,
              area: area > 0 ? area.toFixed(2) : '',
            }))
          : data.habitat;

      // 단일 onChange 일괄 업데이트
      const updates: Partial<OilSpillReportData> = {};
      if (aquacultureRows.length > 0) updates.aquaculture = aquacultureRows;
      if (beachRows.length > 0) updates.beaches = beachRows;
      if (marketRows.length > 0) updates.markets = marketRows;
      if (esiFeatures.length > 0) updates.esi = esiRows;
      if (hasSpecies) updates.species = speciesRows;
      if (habitatFeatures.length > 0) updates.habitat = habitatRows;
      if (Object.keys(updates).length > 0) onChange({ ...data, ...updates });

      setMapVisible(true);
      // 다음 렌더 사이클 후 지도 초기화
      setTimeout(() => {
        if (!mapContainerRef.current) return;
        const map = new maplibregl.Map({
          container: mapContainerRef.current,
          style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
          center: [127.5, 35.5],
          zoom: 8,
          preserveDrawingBuffer: true,
        });
        mapRef.current = map;
        map.on('load', () => {
          // 확산 파티클 — sensitive 레이어 아래 (예측 탭과 동일한 색상 로직)
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          map.addSource('particles', { type: 'geojson', data: particlesGeojson as any });
          // 과거 스텝: 회색 반투명
          map.addLayer({
            id: 'particles-past',
            type: 'circle',
            source: 'particles',
            filter: ['==', ['get', 'isLastStep'], false],
            paint: { 'circle-radius': 2.5, 'circle-color': '#828282', 'circle-opacity': 0.4 },
          });
          // 최신 스텝: 모델별 색상 (OpenDrift=파랑, POSEIDON=빨강)
          map.addLayer({
            id: 'particles-current',
            type: 'circle',
            source: 'particles',
            filter: ['==', ['get', 'isLastStep'], true],
            paint: {
              'circle-radius': 3,
              'circle-color': [
                'case',
                ['==', ['get', 'model'], 'OpenDrift'],
                '#3b82f6',
                ['==', ['get', 'model'], 'POSEIDON'],
                '#ef4444',
                '#06b6d4',
              ],
              'circle-opacity': 0.85,
            },
          });
          // 민감자원 레이어
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          map.addSource('sensitive', { type: 'geojson', data: filteredGeojson as any });
          map.addLayer({
            id: 'sensitive-fill',
            type: 'fill',
            source: 'sensitive',
            filter: ['==', '$type', 'Polygon'],
            paint: { 'fill-color': ['get', '_color'], 'fill-opacity': 0.4 },
          });
          map.addLayer({
            id: 'sensitive-line',
            type: 'line',
            source: 'sensitive',
            filter: ['==', '$type', 'Polygon'],
            paint: { 'line-color': ['get', '_color'], 'line-width': 1.5 },
          });
          map.addLayer({
            id: 'sensitive-circle',
            type: 'circle',
            source: 'sensitive',
            filter: ['==', '$type', 'Point'],
            paint: {
              'circle-radius': 6,
              'circle-color': ['get', '_color'],
              'circle-stroke-width': 1.5,
              'circle-stroke-color': '#fff',
            },
          });
          // fit bounds — spread + sensitive 합산
          const coords: [number, number][] = [];
          const collectCoords = (geom: { type: string; coordinates: unknown }) => {
            if (geom.type === 'Point') {
              coords.push(geom.coordinates as [number, number]);
            } else if (geom.type === 'Polygon') {
              const rings = geom.coordinates as [number, number][][];
              rings[0]?.forEach((c) => coords.push(c));
            } else if (geom.type === 'MultiPolygon') {
              const polys = geom.coordinates as [number, number][][][];
              polys.forEach((rings) => rings[0]?.forEach((c) => coords.push(c)));
            }
          };
          filteredGeojson.features.forEach((f) =>
            collectCoords(f.geometry as { type: string; coordinates: unknown }),
          );
          particlesGeojson.features.forEach((f) => {
            coords.push(f.geometry.coordinates as [number, number]);
          });
          if (coords.length > 0) {
            const lngs = coords.map((c) => c[0]);
            const lats = coords.map((c) => c[1]);
            map.fitBounds(
              [
                [Math.min(...lngs), Math.min(...lats)],
                [Math.max(...lngs), Math.max(...lats)],
              ],
              { padding: 60, maxZoom: 13 },
            );
          }
          // 사고 위치 마커 (캔버스 레이어 — 캡처에 포함)
          if (incLat != null && incLon != null) {
            map.addSource('incident-point', {
              type: 'geojson',
              data: {
                type: 'Feature',
                geometry: { type: 'Point', coordinates: [incLon, incLat] },
                properties: {},
              },
            });
            map.addLayer({
              id: 'incident-circle',
              type: 'circle',
              source: 'incident-point',
              paint: {
                'circle-radius': 7,
                'circle-color': '#ef4444',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ffffff',
              },
            });
            map.addLayer({
              id: 'incident-label',
              type: 'symbol',
              source: 'incident-point',
              layout: {
                'text-field': '사고위치',
                'text-size': 11,
                'text-offset': [0, 1.6],
                'text-anchor': 'top',
                'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
              },
              paint: {
                'text-color': '#ffffff',
                'text-halo-color': '#ef4444',
                'text-halo-width': 3,
              },
            });
          }
        });
      }, 100);
    } catch {
      alert('민감자원 지도 데이터를 불러오지 못했습니다.');
    } finally {
      setLoading(false);
    }
  };

  const handleCapture = () => {
    const map = mapRef.current;
    if (!map) return;
    setCapturing(true);
    map.once('idle', () => {
      const mapCanvas = map.getCanvas();
      const dpr = window.devicePixelRatio || 1;
      const W = mapCanvas.width;
      const H = mapCanvas.height;

      const composite = document.createElement('canvas');
      composite.width = W;
      composite.height = H;
      const ctx = composite.getContext('2d')!;

      // 지도 그리기
      ctx.drawImage(mapCanvas, 0, 0);

      // 범례 그리기
      const items = CATEGORY_COLORS.filter((c) => legendLabels.includes(c.label));
      if (items.length > 0) {
        const pad = 8 * dpr;
        const swSize = 12 * dpr;
        const lineH = 18 * dpr;
        const fontSize = 11 * dpr;
        const boxW = 130 * dpr;
        const boxH = pad * 2 + items.length * lineH;
        const lx = pad,
          ly = pad;

        ctx.fillStyle = 'rgba(255,255,255,0.88)';
        ctx.fillRect(lx, ly, boxW, boxH);
        ctx.strokeStyle = 'rgba(0,0,0,0.15)';
        ctx.lineWidth = dpr;
        ctx.strokeRect(lx, ly, boxW, boxH);

        items.forEach(({ color, label }, i) => {
          const iy = ly + pad + i * lineH;
          ctx.fillStyle = color;
          ctx.fillRect(lx + pad, iy + (lineH - swSize) / 2, swSize, swSize);
          ctx.fillStyle = '#1f2937';
          ctx.font = `${fontSize}px sans-serif`;
          ctx.fillText(label, lx + pad + swSize + 4 * dpr, iy + lineH / 2 + fontSize * 0.35);
        });
      }

      onChange({ ...data, sensitiveMapImage: composite.toDataURL('image/png') });
      setCapturing(false);
    });
    map.triggerRepaint();
  };

  const handleReset = () => {
    if (mapRef.current) {
      mapRef.current.remove();
      mapRef.current = null;
    }
    setMapVisible(false);
    setLegendLabels([]);
    onChange({ ...data, sensitiveMapImage: undefined });
  };

  useEffect(() => {
    return () => {
      mapRef.current?.remove();
    };
  }, []);

  // 뷰 모드: 이미지 있으면 표시, 없으면 플레이스홀더
  if (!editing) {
    if (data.sensitiveMapImage) {
      return (
        <img
          src={data.sensitiveMapImage}
          alt="민감자원 분포 지도"
          style={{
            width: '100%',
            height: 'auto',
            display: 'block',
            border: '1px solid #ddd',
            borderRadius: 4,
          }}
        />
      );
    }
    return <div style={S.mapPlaceholder}>민감자원 분포(10km 내) 지도</div>;
  }

  // 편집 모드: acdntSn 없음
  if (!acdntSn) {
    return <div style={S.mapPlaceholder}>민감자원 분포(10km 내) 지도</div>;
  }

  // 편집 모드: 캡처 이미지 있음
  if (data.sensitiveMapImage) {
    return (
      <div style={{ position: 'relative' }}>
        <img
          src={data.sensitiveMapImage}
          alt="민감자원 분포 지도"
          style={{
            width: '100%',
            height: 'auto',
            display: 'block',
            border: '1px solid #ddd',
            borderRadius: 4,
          }}
        />
        <button
          onClick={handleReset}
          style={{
            position: 'absolute',
            top: 8,
            right: 8,
            background: 'rgba(0,0,0,0.6)',
            color: '#fff',
            border: 'none',
            borderRadius: 4,
            padding: '3px 8px',
            fontSize: 11,
            cursor: 'pointer',
          }}
        >
          재캡처
        </button>
      </div>
    );
  }

  // 편집 모드: 지도 로드/캡처
  return (
    <div>
      {!mapVisible ? (
        <div style={{ ...S.mapPlaceholder, flexDirection: 'column', gap: 8 }}>
          <span>민감자원 분포(10km 내) 지도</span>
          <button
            onClick={handleLoad}
            disabled={loading}
            style={{
              background: '#0891b2',
              color: '#fff',
              border: 'none',
              borderRadius: 4,
              padding: '5px 14px',
              fontSize: 12,
              cursor: loading ? 'not-allowed' : 'pointer',
              opacity: loading ? 0.7 : 1,
            }}
          >
            {loading ? '불러오는 중...' : '지도 불러오기'}
          </button>
        </div>
      ) : (
        <div style={{ position: 'relative' }}>
          <div
            ref={mapContainerRef}
            style={{ width: '100%', height: 440, borderRadius: 4, overflow: 'hidden' }}
          />
          {legendLabels.length > 0 && (
            <div
              style={{
                position: 'absolute',
                top: 8,
                left: 8,
                background: 'rgba(255,255,255,0.88)',
                border: '1px solid rgba(0,0,0,0.15)',
                borderRadius: 4,
                padding: '6px 10px',
                pointerEvents: 'none',
              }}
            >
              {CATEGORY_COLORS.filter((c) => legendLabels.includes(c.label)).map(
                ({ color, label }) => (
                  <div
                    key={label}
                    style={{
                      display: 'flex',
                      alignItems: 'center',
                      gap: 6,
                      marginBottom: 3,
                      fontSize: 11,
                      color: '#1f2937',
                      whiteSpace: 'nowrap',
                    }}
                  >
                    <div style={{ width: 12, height: 12, background: color, flexShrink: 0 }} />
                    {label}
                  </div>
                ),
              )}
            </div>
          )}
          <div style={{ display: 'flex', gap: 8, marginTop: 6, justifyContent: 'flex-end' }}>
            <button
              onClick={handleReset}
              style={{
                background: 'transparent',
                color: '#6b7280',
                border: '1px solid #374151',
                borderRadius: 4,
                padding: '3px 10px',
                fontSize: 11,
                cursor: 'pointer',
              }}
            >
              취소
            </button>
            <button
              onClick={handleCapture}
              disabled={capturing}
              style={{
                background: '#0891b2',
                color: '#fff',
                border: 'none',
                borderRadius: 4,
                padding: '3px 12px',
                fontSize: 11,
                cursor: capturing ? 'not-allowed' : 'pointer',
                opacity: capturing ? 0.7 : 1,
              }}
            >
              {capturing ? '캡처 중...' : '이 화면으로 캡처'}
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

function Page4({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const setArr = <T extends Record<string, string>>(
    key: keyof OilSpillReportData,
    arr: T[],
    i: number,
    k: string,
    v: string,
  ) => {
    const copy = [...arr];
    copy[i] = { ...copy[i], [k]: v };
    onChange({ ...data, [key]: copy });
  };

  return (
    <div style={S.page}>
      <div className="absolute top-2.5 right-4 text-caption text-fg-disabled font-semibold">
        해양오염방제지원시스템
      </div>
      <div style={S.sectionTitle}>4. 민감자원 및 민감도 평가</div>
      <SensitiveResourceMapSection data={data} editing={editing} onChange={onChange} />

      <div style={{ ...S.subHeader, marginTop: '16px' }}>양식장 분포</div>
      <table style={S.table}>
        <thead>
          <tr>
            <th style={S.th}>구분</th>
            <th style={S.th}>면적(ha)</th>
            <th style={S.th}>사고지점과의 거리(km)</th>
          </tr>
        </thead>
        <tbody>
          {data.aquaculture.map((a, i) => (
            <tr key={i}>
              <ECell
                value={a.type}
                editing={editing}
                onChange={(v) => setArr('aquaculture', data.aquaculture, i, 'type', v)}
                placeholder="-"
              />
              <ECell
                value={a.area}
                editing={editing}
                onChange={(v) => setArr('aquaculture', data.aquaculture, i, 'area', v)}
              />
              <ECell
                value={a.distance}
                editing={editing}
                onChange={(v) => setArr('aquaculture', data.aquaculture, i, 'distance', v)}
              />
            </tr>
          ))}
        </tbody>
      </table>
      {editing && (
        <AddRowBtn
          onClick={() =>
            onChange({
              ...data,
              aquaculture: [...data.aquaculture, { type: '', area: '', distance: '' }],
            })
          }
        />
      )}

      <div className="grid grid-cols-2 gap-5">
        <div>
          <div style={S.subHeader}>해수욕장 분포</div>
          <table style={S.table}>
            <thead>
              <tr>
                <th style={S.th}>구분</th>
                <th style={S.th}>이격거리(km)</th>
              </tr>
            </thead>
            <tbody>
              {data.beaches.map((b, i) => (
                <tr key={i}>
                  <ECell
                    value={b.name}
                    editing={editing}
                    onChange={(v) => setArr('beaches', data.beaches, i, 'name', v)}
                    align="left"
                  />
                  <ECell
                    value={b.distance}
                    editing={editing}
                    onChange={(v) => setArr('beaches', data.beaches, i, 'distance', v)}
                  />
                </tr>
              ))}
            </tbody>
          </table>
          {editing && (
            <AddRowBtn
              onClick={() =>
                onChange({ ...data, beaches: [...data.beaches, { name: '', distance: '' }] })
              }
            />
          )}
        </div>
        <div>
          <div style={S.subHeader}>수산시장 분포</div>
          <table style={S.table}>
            <thead>
              <tr>
                <th style={S.th}>구분</th>
                <th style={S.th}>이격거리(km)</th>
              </tr>
            </thead>
            <tbody>
              {data.markets.map((m, i) => (
                <tr key={i}>
                  <ECell
                    value={m.name}
                    editing={editing}
                    onChange={(v) => setArr('markets', data.markets, i, 'name', v)}
                    align="left"
                  />
                  <ECell
                    value={m.distance}
                    editing={editing}
                    onChange={(v) => setArr('markets', data.markets, i, 'distance', v)}
                  />
                </tr>
              ))}
            </tbody>
          </table>
          {editing && (
            <AddRowBtn
              onClick={() =>
                onChange({ ...data, markets: [...data.markets, { name: '', distance: '' }] })
              }
            />
          )}
        </div>
      </div>

      <div className="grid grid-cols-2 gap-5 mt-2">
        <div>
          <div style={S.subHeader}>해안선(ESI) 분포</div>
          <table style={S.table}>
            <thead>
              <tr>
                <th style={S.th}>구분</th>
                <th style={S.th}>유형</th>
                <th style={S.th}>분포 길이</th>
              </tr>
            </thead>
            <tbody>
              {data.esi.map((e, i) => (
                <tr key={i}>
                  <td style={{ ...S.td, fontWeight: 600, fontSize: 'var(--font-size-caption)' }}>
                    {e.code}
                  </td>
                  <td style={S.tdLeft}>{e.type}</td>
                  <ECell
                    value={e.length}
                    editing={editing}
                    onChange={(v) => setArr('esi', data.esi, i, 'length', v)}
                  />
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div>
          <div style={S.subHeader}>생물종(보호종) 분포</div>
          <table style={S.table}>
            <thead>
              <tr>
                <th style={S.th}>구분</th>
                <th style={S.th}>종</th>
              </tr>
            </thead>
            <tbody>
              {data.species.map((s, i) => (
                <tr key={i}>
                  <td style={{ ...S.td, fontWeight: 600 }}>{s.category}</td>
                  <ECell
                    value={s.species}
                    editing={editing}
                    onChange={(v) => setArr('species', data.species, i, 'species', v)}
                    align="left"
                    placeholder="-"
                  />
                </tr>
              ))}
            </tbody>
          </table>
          <div style={{ ...S.subHeader, marginTop: '16px' }}>서식지 분포</div>
          <table style={S.table}>
            <thead>
              <tr>
                <th style={S.th}>구분</th>
                <th style={S.th}>분포넓이</th>
              </tr>
            </thead>
            <tbody>
              {data.habitat.map((h, i) => (
                <tr key={i}>
                  <ECell
                    value={h.type}
                    editing={editing}
                    onChange={(v) => setArr('habitat', data.habitat, i, 'type', v)}
                  />
                  <ECell
                    value={h.area}
                    editing={editing}
                    onChange={(v) => setArr('habitat', data.habitat, i, 'area', v)}
                  />
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

const SENS_LEVELS = [
  { key: 5, level: '매우 높음', color: '#ef4444' },
  { key: 4, level: '높음', color: '#f97316' },
  { key: 3, level: '보통', color: '#eab308' },
  { key: 2, level: '낮음', color: '#22c55e' },
];

function SensitivityMapSection({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const mapContainerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<maplibregl.Map | null>(null);
  const [mapVisible, setMapVisible] = useState(false);
  const [loading, setLoading] = useState(false);
  const [capturing, setCapturing] = useState(false);
  const acdntSn = data.acdntSn;

  const handleLoad = async () => {
    if (!acdntSn) return;
    setLoading(true);
    try {
      const geojson = await fetchSensitivityEvaluationGeojson(acdntSn);
      const seasonKey = getSeasonKey(data.incident.occurTime);

      // 레벨 계산 및 면적 집계 (레벨 1 제외)
      const areaByLevel: Record<number, number> = {};
      geojson.features.forEach((f) => {
        const p = (f as { properties: Record<string, unknown> }).properties;
        const lvl = Number(p[seasonKey] ?? 1);
        if (lvl >= 2) areaByLevel[lvl] = (areaByLevel[lvl] ?? 0) + Number(p['area_km2'] ?? 0);
      });
      const sensitivityRows = SENS_LEVELS.map((s) => ({
        level: s.level,
        color: s.color,
        area: areaByLevel[s.key] != null ? areaByLevel[s.key].toFixed(2) : '',
      }));
      onChange({ ...data, sensitivity: sensitivityRows });

      // 레벨 속성 추가 + 레벨 1 제외한 표시용 GeoJSON
      const displayGeojson = {
        ...geojson,
        features: geojson.features
          .map((f) => {
            const p = (f as { properties: Record<string, unknown> }).properties;
            return { ...(f as object), properties: { ...p, level: Number(p[seasonKey] ?? 1) } };
          })
          .filter((f) => (f as { properties: { level: number } }).properties.level >= 2),
      };

      setMapVisible(true);
      setTimeout(() => {
        if (!mapContainerRef.current) return;
        const map = new maplibregl.Map({
          container: mapContainerRef.current,
          style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
          center: [127.5, 35.5],
          zoom: 8,
          preserveDrawingBuffer: true,
        });
        mapRef.current = map;
        map.on('load', () => {
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          map.addSource('sensitivity', { type: 'geojson', data: displayGeojson as any });
          const colorExpr: maplibregl.ExpressionSpecification = [
            'case',
            ['==', ['get', 'level'], 5],
            '#ef4444',
            ['==', ['get', 'level'], 4],
            '#f97316',
            ['==', ['get', 'level'], 3],
            '#eab308',
            ['==', ['get', 'level'], 2],
            '#22c55e',
            'transparent',
          ];
          map.addLayer({
            id: 'sensitivity-fill',
            type: 'fill',
            source: 'sensitivity',
            filter: ['==', '$type', 'Polygon'],
            paint: { 'fill-color': colorExpr, 'fill-opacity': 0.6 },
          });
          map.addLayer({
            id: 'sensitivity-line',
            type: 'line',
            source: 'sensitivity',
            filter: ['==', '$type', 'Polygon'],
            paint: { 'line-color': colorExpr, 'line-width': 0.5, 'line-opacity': 0.4 },
          });
          map.addLayer({
            id: 'sensitivity-circle',
            type: 'circle',
            source: 'sensitivity',
            filter: ['==', '$type', 'Point'],
            paint: { 'circle-radius': 5, 'circle-color': colorExpr },
          });

          // fitBounds
          const coords: [number, number][] = [];
          displayGeojson.features.forEach((f) => {
            const geom = (f as { geometry: { type: string; coordinates: unknown } }).geometry;
            if (geom.type === 'Point') coords.push(geom.coordinates as [number, number]);
            else if (geom.type === 'Polygon')
              (geom.coordinates as [number, number][][])[0]?.forEach((c) => coords.push(c));
            else if (geom.type === 'MultiPolygon')
              (geom.coordinates as [number, number][][][]).forEach((rings) =>
                rings[0]?.forEach((c) => coords.push(c)),
              );
          });
          if (coords.length > 0) {
            const lngs = coords.map((c) => c[0]);
            const lats = coords.map((c) => c[1]);
            map.fitBounds(
              [
                [Math.min(...lngs), Math.min(...lats)],
                [Math.max(...lngs), Math.max(...lats)],
              ],
              { padding: 60, maxZoom: 13 },
            );
          }
          // 사고 위치 마커 (캔버스 레이어 — 캡처에 포함)
          const incLat = parseCoord(data.incident.lat);
          const incLon = parseCoord(data.incident.lon);
          if (incLat != null && incLon != null) {
            map.addSource('incident-point', {
              type: 'geojson',
              data: {
                type: 'Feature',
                geometry: { type: 'Point', coordinates: [incLon, incLat] },
                properties: {},
              },
            });
            map.addLayer({
              id: 'incident-circle',
              type: 'circle',
              source: 'incident-point',
              paint: {
                'circle-radius': 7,
                'circle-color': '#ef4444',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ffffff',
              },
            });
            map.addLayer({
              id: 'incident-label',
              type: 'symbol',
              source: 'incident-point',
              layout: {
                'text-field': '사고위치',
                'text-size': 11,
                'text-offset': [0, 1.6],
                'text-anchor': 'top',
                'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
              },
              paint: {
                'text-color': '#ffffff',
                'text-halo-color': '#ef4444',
                'text-halo-width': 3,
              },
            });
          }
        });
      }, 100);
    } catch {
      alert('통합민감도 평가 데이터를 불러오지 못했습니다.');
    } finally {
      setLoading(false);
    }
  };

  const handleCapture = () => {
    const map = mapRef.current;
    if (!map) return;
    setCapturing(true);
    map.once('idle', () => {
      const dataUrl = map.getCanvas().toDataURL('image/png');
      onChange({ ...data, sensitivityMapImage: dataUrl });
      setCapturing(false);
    });
    map.triggerRepaint();
  };

  const handleReset = () => {
    if (mapRef.current) {
      mapRef.current.remove();
      mapRef.current = null;
    }
    setMapVisible(false);
    onChange({ ...data, sensitivityMapImage: undefined });
  };

  useEffect(() => {
    return () => {
      mapRef.current?.remove();
    };
  }, []);

  if (!editing) {
    if (data.sensitivityMapImage) {
      return (
        <img
          src={data.sensitivityMapImage}
          alt="통합민감도 평가 지도"
          style={{
            width: '100%',
            height: 'auto',
            display: 'block',
            border: '1px solid #ddd',
            borderRadius: 4,
            marginBottom: 16,
          }}
        />
      );
    }
    return <div style={S.mapPlaceholder}>통합민감도 평가 지도</div>;
  }

  if (!acdntSn) return <div style={S.mapPlaceholder}>통합민감도 평가 지도</div>;

  if (data.sensitivityMapImage) {
    return (
      <div style={{ position: 'relative' }}>
        <img
          src={data.sensitivityMapImage}
          alt="통합민감도 평가 지도"
          style={{
            width: '100%',
            height: 'auto',
            display: 'block',
            border: '1px solid #ddd',
            borderRadius: 4,
          }}
        />
        <button
          onClick={handleReset}
          style={{
            position: 'absolute',
            top: 8,
            right: 8,
            background: 'rgba(0,0,0,0.6)',
            color: '#fff',
            border: 'none',
            borderRadius: 4,
            padding: '3px 8px',
            fontSize: 11,
            cursor: 'pointer',
          }}
        >
          재캡처
        </button>
      </div>
    );
  }

  return (
    <div style={{ position: 'relative' }}>
      {!mapVisible ? (
        <div style={{ ...S.mapPlaceholder, flexDirection: 'column', gap: 8 }}>
          <span>민감도 분포(10km내) 지도</span>
          <button
            onClick={handleLoad}
            disabled={loading}
            style={{
              background: '#0891b2',
              color: '#fff',
              border: 'none',
              borderRadius: 4,
              padding: '5px 14px',
              fontSize: 12,
              cursor: loading ? 'not-allowed' : 'pointer',
              opacity: loading ? 0.7 : 1,
            }}
          >
            {loading ? '불러오는 중...' : '지도 불러오기'}
          </button>
        </div>
      ) : (
        <div style={{ position: 'relative' }}>
          <div
            ref={mapContainerRef}
            style={{ width: '100%', height: 440, borderRadius: 4, overflow: 'hidden' }}
          />
          <div style={{ display: 'flex', gap: 8, marginTop: 6, justifyContent: 'flex-end' }}>
            <button
              onClick={handleReset}
              style={{
                background: 'transparent',
                color: '#6b7280',
                border: '1px solid #374151',
                borderRadius: 4,
                padding: '3px 10px',
                fontSize: 11,
                cursor: 'pointer',
              }}
            >
              취소
            </button>
            <button
              onClick={handleCapture}
              disabled={capturing}
              style={{
                background: '#0891b2',
                color: '#fff',
                border: 'none',
                borderRadius: 4,
                padding: '3px 12px',
                fontSize: 11,
                cursor: capturing ? 'not-allowed' : 'pointer',
                opacity: capturing ? 0.7 : 1,
              }}
            >
              {capturing ? '캡처 중...' : '이 화면으로 캡처'}
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

function Page5({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const setSens = (i: number, v: string) => {
    const s = [...data.sensitivity];
    s[i] = { ...s[i], area: v };
    onChange({ ...data, sensitivity: s });
  };
  return (
    <div style={S.page}>
      <div className="absolute top-2.5 right-4 text-caption text-fg-disabled font-semibold">
        해양오염방제지원시스템
      </div>
      <div style={S.sectionTitle}>통합민감도 평가 (해당 계절)</div>
      <SensitivityMapSection data={data} editing={editing} onChange={onChange} />
      <table style={S.table}>
        <thead>
          <tr>
            <th style={S.th}>민감도</th>
            <th style={S.th}>분포 면적(km²)</th>
          </tr>
        </thead>
        <tbody>
          {data.sensitivity.map((s, i) => (
            <tr key={i}>
              <td style={{ ...S.td, fontWeight: 700 }}>
                <span
                  style={{
                    display: 'inline-block',
                    width: 10,
                    height: 10,
                    borderRadius: 2,
                    background: s.color,
                    marginRight: 8,
                    verticalAlign: 'middle',
                  }}
                />
                {s.level}
              </td>
              <ECell value={s.area} editing={editing} onChange={(v) => setSens(i, v)} />
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function Page6({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const setVessel = (i: number, k: string, v: string) => {
    const vs = [...data.vessels];
    vs[i] = { ...vs[i], [k]: v };
    onChange({ ...data, vessels: vs });
  };
  return (
    <div style={S.page}>
      <div className="absolute top-2.5 right-4 text-caption text-fg-disabled font-semibold">
        해양오염방제지원시스템
      </div>
      <div style={S.sectionTitle}>5. 방제전략 수립·실행</div>
      <div style={S.subHeader}>방제자원 배치 현황 (반경 30km내)</div>
      <div className="overflow-x-auto">
        <table style={S.table}>
          <thead>
            <tr>
              <th style={S.th} rowSpan={2}>
                #
              </th>
              <th style={S.th} rowSpan={2}>
                선명
              </th>
              <th style={S.th} rowSpan={2}>
                소속
              </th>
              <th style={S.th} rowSpan={2}>
                거리(km)
              </th>
              <th style={S.th} rowSpan={2}>
                속력(knots)
              </th>
              <th style={S.th} rowSpan={2}>
                크기(총톤수)
              </th>
              <th style={S.th} colSpan={2}>
                유회수기
              </th>
              <th style={S.th} colSpan={2}>
                오일펜스
              </th>
            </tr>
            <tr>
              <th style={S.th}>종류</th>
              <th style={S.th}>용량(kl)</th>
              <th style={S.th}>종류</th>
              <th style={S.th}>길이(m)</th>
            </tr>
          </thead>
          <tbody>
            {data.vessels.map((v, i) => (
              <tr key={i}>
                <td style={{ ...S.td, fontWeight: 600 }}>{i + 1}</td>
                <ECell
                  value={v.name}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'name', val)}
                />
                <ECell
                  value={v.org}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'org', val)}
                />
                <ECell
                  value={v.dist}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'dist', val)}
                />
                <ECell
                  value={v.speed}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'speed', val)}
                />
                <ECell
                  value={v.ton}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'ton', val)}
                />
                <ECell
                  value={v.collectorType}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'collectorType', val)}
                />
                <ECell
                  value={v.collectorCap}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'collectorCap', val)}
                />
                <ECell
                  value={v.boomType}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'boomType', val)}
                />
                <ECell
                  value={v.boomLength}
                  editing={editing}
                  onChange={(val) => setVessel(i, 'boomLength', val)}
                />
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      {editing && (
        <AddRowBtn
          onClick={() =>
            onChange({
              ...data,
              vessels: [
                ...data.vessels,
                {
                  name: '',
                  org: '',
                  dist: '',
                  speed: '',
                  ton: '',
                  collectorType: '',
                  collectorCap: '',
                  boomType: '',
                  boomLength: '',
                },
              ],
            })
          }
        />
      )}
      <div style={S.subHeader}>기타 장비</div>
      {editing ? (
        <textarea
          value={data.etcEquipment}
          onChange={(e) => onChange({ ...data, etcEquipment: e.target.value })}
          placeholder="기타 장비 입력"
          style={{
            width: '100%',
            minHeight: '60px',
            background: 'var(--bg-base)',
            border: '1px solid var(--stroke-light)',
            borderRadius: '4px',
            padding: '12px',
            fontSize: 'var(--font-size-label-1)',
            outline: 'none',
            resize: 'vertical',
          }}
        />
      ) : (
        <div
          style={{
            minHeight: '60px',
            border: data.etcEquipment
              ? '1px solid var(--stroke-default)'
              : '2px dashed var(--stroke-default)',
            borderRadius: '4px',
            padding: '12px',
            color: data.etcEquipment ? 'var(--fg-default)' : 'var(--fg-disabled)',
            fontStyle: data.etcEquipment ? 'normal' : 'italic',
            fontSize: 'var(--font-size-label-1)',
          }}
        >
          {data.etcEquipment || '-'}
        </div>
      )}
    </div>
  );
}

function Page7({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const setRec = (i: number, k: string, v: string) => {
    const r = [...data.recovery];
    r[i] = { ...r[i], [k]: v };
    onChange({ ...data, recovery: r });
  };
  const setRes = (k: string, v: string) =>
    onChange({ ...data, result: { ...data.result, [k]: v } });
  return (
    <div style={S.page}>
      <div className="absolute top-2.5 right-4 text-caption text-fg-disabled font-semibold">
        해양오염방제지원시스템
      </div>
      <div style={S.sectionTitle}>방제선/자원 동원 결과</div>
      <div style={S.mapPlaceholder}>방제선/자원 동원 결과 지도</div>
      <div style={S.subHeader}>기름회수량</div>
      <table style={S.table}>
        <thead>
          <tr>
            <th style={S.th}>선명</th>
            <th style={S.th}>작업기간(회수작업 시작시간+시간)</th>
          </tr>
        </thead>
        <tbody>
          {data.recovery.map((r, i) => (
            <tr key={i}>
              <ECell
                value={r.shipName}
                editing={editing}
                onChange={(v) => setRec(i, 'shipName', v)}
              />
              <ECell value={r.period} editing={editing} onChange={(v) => setRec(i, 'period', v)} />
            </tr>
          ))}
        </tbody>
      </table>
      {editing && (
        <AddRowBtn
          onClick={() =>
            onChange({ ...data, recovery: [...data.recovery, { shipName: '', period: '' }] })
          }
        />
      )}
      <div style={S.subHeader}>동원 방제선 내역</div>
      <table style={S.table}>
        <thead>
          <tr>
            <th style={S.th}>유출량(kl)</th>
            <th style={S.th}>누적풍화량(kl)</th>
            <th style={S.th}>누적회수량(kl)</th>
            <th style={S.th}>누적해상잔존량(kl)</th>
            <th style={S.th}>누적연안부착량(kl)</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <ECell
              value={data.result.spillTotal}
              editing={editing}
              onChange={(v) => setRes('spillTotal', v)}
            />
            <ECell
              value={data.result.weatheredTotal}
              editing={editing}
              onChange={(v) => setRes('weatheredTotal', v)}
            />
            <ECell
              value={data.result.recoveredTotal}
              editing={editing}
              onChange={(v) => setRes('recoveredTotal', v)}
            />
            <ECell
              value={data.result.seaRemainTotal}
              editing={editing}
              onChange={(v) => setRes('seaRemainTotal', v)}
            />
            <ECell
              value={data.result.coastAttachTotal}
              editing={editing}
              onChange={(v) => setRes('coastAttachTotal', v)}
            />
          </tr>
        </tbody>
      </table>
    </div>
  );
}

// ─── Main Template Component ────────────────────────────────
interface Props {
  mode: 'preview' | 'edit' | 'view';
  initialData?: OilSpillReportData;
  onSave?: (data: OilSpillReportData) => void;
  onBack?: () => void;
}

export function OilSpillReportTemplate({ mode, initialData, onSave, onBack }: Props) {
  const [data, setData] = useState<OilSpillReportData>(() => initialData || createSampleReport());
  const [currentPage, setCurrentPage] = useState(0);
  const [viewMode, setViewMode] = useState<'page' | 'all'>('all');
  const editing = mode === 'edit';

  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect
    if (initialData) setData(initialData);
  }, [initialData]);

  const handleSave = useCallback(async () => {
    let reportData = data;
    if (!data.title) {
      const title = data.incident.name || `보고서 ${new Date().toLocaleDateString('ko-KR')}`;
      reportData = { ...data, title };
    }
    try {
      await saveReport(reportData);
      onSave?.(reportData);
    } catch (err) {
      console.error('[reports] 저장 오류:', err);
      alert('보고서 저장 중 오류가 발생했습니다.');
    }
  }, [data, onSave]);

  const pages = [
    { label: '1. 사고 정보', node: <Page1 data={data} editing={editing} onChange={setData} /> },
    {
      label: '2. 해양기상 + 확산예측',
      node: <Page2 data={data} editing={editing} onChange={setData} />,
    },
    { label: '3. 분석', node: <Page3 data={data} editing={editing} onChange={setData} /> },
    { label: '4. 민감자원', node: <Page4 data={data} editing={editing} onChange={setData} /> },
    { label: '5. 통합민감도', node: <Page5 data={data} editing={editing} onChange={setData} /> },
    { label: '6. 방제전략', node: <Page6 data={data} editing={editing} onChange={setData} /> },
    { label: '7. 동원 결과', node: <Page7 data={data} editing={editing} onChange={setData} /> },
  ];

  return (
    <div className="w-full">
      {/* Toolbar */}
      <div className="flex items-center justify-between mb-5 flex-wrap gap-3">
        <div className="flex items-center gap-2.5">
          {onBack && (
            <button
              onClick={onBack}
              className="px-3 py-1.5 text-label-1 font-semibold text-fg-sub bg-transparent border-none cursor-pointer"
            >
              ← 돌아가기
            </button>
          )}
          <h2 className="text-title-1 font-bold">
            {editing ? (
              <input
                value={data.title}
                onChange={(e) => setData({ ...data, title: e.target.value })}
                placeholder="보고서 제목 입력"
                className="text-title-1 font-bold bg-bg-base border border-[var(--stroke-light)] rounded px-2.5 py-1 outline-none w-full max-w-[600px]"
              />
            ) : (
              data.title || '유류오염사고 대응지원 상황도'
            )}
          </h2>
          <span
            className="px-2.5 py-[3px] text-label-2 font-semibold rounded border"
            style={
              editing
                ? {
                    background: 'rgba(251,191,36,0.15)',
                    color: '#f59e0b',
                    borderColor: 'rgba(251,191,36,0.3)',
                  }
                : {
                    background: 'rgba(6,182,212,0.15)',
                    color: 'var(--color-accent)',
                    borderColor: 'rgba(6,182,212,0.3)',
                  }
            }
          >
            {editing ? '편집 중' : mode === 'preview' ? '샘플' : '보기'}
          </span>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={() => setViewMode('all')}
            className="px-3.5 py-1.5 text-label-2 font-semibold rounded cursor-pointer"
            style={{
              border:
                viewMode === 'all'
                  ? '1px solid var(--color-accent)'
                  : '1px solid var(--stroke-default)',
              background: viewMode === 'all' ? 'rgba(6,182,212,0.1)' : 'var(--bg-elevated)',
              color: viewMode === 'all' ? 'var(--color-accent)' : 'var(--fg-disabled)',
            }}
          >
            전체 보기
          </button>
          <button
            onClick={() => setViewMode('page')}
            className="px-3.5 py-1.5 text-label-2 font-semibold rounded cursor-pointer"
            style={{
              border:
                viewMode === 'page'
                  ? '1px solid var(--color-accent)'
                  : '1px solid var(--stroke-default)',
              background: viewMode === 'page' ? 'rgba(6,182,212,0.1)' : 'var(--bg-elevated)',
              color: viewMode === 'page' ? 'var(--color-accent)' : 'var(--fg-disabled)',
            }}
          >
            페이지별
          </button>
          {editing && (
            <button
              onClick={handleSave}
              className="px-4 py-1.5 text-label-2 font-bold rounded cursor-pointer border border-[#22c55e] bg-[rgba(34,197,94,0.15)] text-color-success"
            >
              저장
            </button>
          )}
          <button
            onClick={() => window.print()}
            className="px-3.5 py-1.5 text-label-2 font-semibold rounded cursor-pointer border border-[var(--color-danger)] bg-[rgba(239,68,68,0.1)] text-color-danger"
          >
            인쇄 / PDF
          </button>
        </div>
      </div>

      {/* Page tabs */}
      {viewMode === 'page' && (
        <div className="flex gap-1 mb-4 flex-wrap">
          {pages.map((p, i) => (
            <button
              key={i}
              onClick={() => setCurrentPage(i)}
              className="px-3 py-1.5 text-label-2 font-semibold rounded cursor-pointer"
              style={{
                border:
                  currentPage === i
                    ? '1px solid var(--color-accent)'
                    : '1px solid var(--stroke-default)',
                background: currentPage === i ? 'rgba(6,182,212,0.15)' : 'transparent',
                color: currentPage === i ? 'var(--color-accent)' : 'var(--fg-disabled)',
              }}
            >
              {p.label}
            </button>
          ))}
        </div>
      )}

      {/* Pages */}
      <div id="report-print-area" className="w-full">
        {viewMode === 'all' ? (
          pages.map((p, i) => <div key={i}>{p.node}</div>)
        ) : (
          <div>
            {pages[currentPage].node}
            <div className="flex justify-center gap-2 mt-4">
              <button
                onClick={() => setCurrentPage((p) => Math.max(0, p - 1))}
                disabled={currentPage === 0}
                className="px-5 py-2 text-label-1 font-semibold rounded border border-stroke bg-bg-elevated cursor-pointer"
                style={{
                  color: currentPage === 0 ? 'var(--fg-disabled)' : 'var(--fg-default)',
                  opacity: currentPage === 0 ? 0.4 : 1,
                }}
              >
                이전
              </button>
              <span className="px-4 py-2 text-label-1 text-fg-sub">
                {currentPage + 1} / {pages.length}
              </span>
              <button
                onClick={() => setCurrentPage((p) => Math.min(pages.length - 1, p + 1))}
                disabled={currentPage === pages.length - 1}
                className="px-5 py-2 text-label-1 font-semibold rounded cursor-pointer"
                style={{
                  border: '1px solid var(--color-accent)',
                  background: 'rgba(6,182,212,0.1)',
                  color:
                    currentPage === pages.length - 1 ? 'var(--fg-disabled)' : 'var(--color-accent)',
                  opacity: currentPage === pages.length - 1 ? 0.4 : 1,
                }}
              >
                다음
              </button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
