import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import {
  LineChart,
  Line,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
  ScatterChart,
  Scatter,
  ZAxis,
  Cell,
} from 'recharts';
import type { TooltipProps } from 'recharts';
import type { SeismicDto, PressureDto } from '../../services/sensorApi';

interface Props {
  seismicData: SeismicDto[];
  pressureData: PressureDto[];
  currentTime: number;
  historyMinutes: number;
  onSeismicClick?: (lat: number, lng: number, magnitude: number, place: string) => void;
}

const MINUTE = 60_000;
const BUCKET_COUNT = 48;

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

function buildTicks(currentTime: number, historyMinutes: number): number[] {
  const interval = historyMinutes * MINUTE;
  const ticks: number[] = [];
  for (let i = 8; i >= 0; i--) {
    ticks.push(currentTime - i * interval);
  }
  return ticks;
}

/**
 * 지진 데이터: 버킷이 아닌 실제 이벤트 포인트로 변환
 */
function prepareSeismicPoints(
  data: SeismicDto[],
  rangeStart: number,
  rangeEnd: number,
): { time: number; magnitude: number; place: string; lat: number; lng: number }[] {
  return data
    .filter(ev => ev.timestamp >= rangeStart && ev.timestamp <= rangeEnd)
    .map(ev => ({ time: ev.timestamp, magnitude: ev.magnitude, place: ev.place, lat: ev.lat, lng: ev.lng }));
}

/**
 * 기압 데이터: 원본 시간 포인트를 관측소별 컬럼으로 통합
 * 동일 timestamp의 관측소 데이터를 하나의 row로 합침
 * 버킷 없이 원본 그대로 사용하여 히스토리 범위와 무관하게 일관된 그래프 표시
 */
function preparePressureMerged(
  data: PressureDto[],
  rangeStart: number,
  rangeEnd: number,
): { time: number; [station: string]: number | null }[] {
  // 범위 내 데이터만 필터
  const filtered = data.filter(r => r.timestamp >= rangeStart && r.timestamp <= rangeEnd);
  const stations = new Set<string>();
  for (const r of filtered) stations.add(r.station);

  // timestamp별 그룹핑 (해수면 보정 적용)
  const timeMap = new Map<number, Record<string, number>>();
  for (const r of filtered) {
    if (!timeMap.has(r.timestamp)) timeMap.set(r.timestamp, {});
    const alt = STATION_ALTITUDE[r.station] ?? 0;
    timeMap.get(r.timestamp)![r.station] = toSeaLevelPressure(r.pressureHpa, alt);
  }

  // 시간순 정렬하여 row 배열 생성
  const stationList = Array.from(stations);
  const times = Array.from(timeMap.keys()).sort((a, b) => a - b);
  return times.map(t => {
    const vals = timeMap.get(t)!;
    const row: Record<string, number | null> = { time: t };
    for (const s of stationList) {
      row[s] = vals[s] ?? null;
    }
    return row as { time: number; [station: string]: number | null };
  });
}

function generateDemoData(
  rangeStart: number,
  rangeEnd: number,
  baseValue: number,
  variance: number,
): { time: number; value: number }[] {
  const bucketSize = (rangeEnd - rangeStart) / BUCKET_COUNT;
  return Array.from({ length: BUCKET_COUNT }, (_, i) => {
    const t = rangeStart + (i + 0.5) * bucketSize;
    const seed = Math.sin(t / 100_000) * 10000;
    const noise = (seed - Math.floor(seed)) * 2 - 1;
    return { time: t, value: Math.max(0, baseValue + noise * variance) };
  });
}

const STATION_COLORS: Record<string, string> = {
  'tehran': '#ef4444',
  'isfahan': '#f97316',
  'bandar-abbas': '#3b82f6',
  'shiraz': '#22c55e',
  'tabriz': '#a855f7',
};

// 관측소 고도(m) — 해수면 기압 보정용
const STATION_ALTITUDE: Record<string, number> = {
  'tehran': 1190,
  'isfahan': 1590,
  'bandar-abbas': 10,
  'shiraz': 1486,
  'tabriz': 1352,
};

// 기압 해수면 보정 (barometric formula 근사)
// SLP ≈ station_pressure × (1 + 0.0065 × altitude / (temperature + 0.0065 × altitude + 273.15))^5.257
// 간단 근사: SLP ≈ station_pressure + altitude / 8.3 (1 hPa per 8.3m at low altitude)
function toSeaLevelPressure(stationHpa: number, altitudeM: number): number {
  return stationHpa + altitudeM / 8.3;
}

const MAGNITUDE_COLORS = ['#fbbf24', '#f97316', '#ef4444', '#dc2626', '#991b1b'];
const TOOLTIP_STYLE = {
  contentStyle: { background: '#1a1a2e', border: '1px solid #333', fontSize: 10, color: '#e0e0e0', padding: '4px 8px' },
  itemStyle: { color: '#e0e0e0' },
  labelStyle: { color: '#aaa' },
  wrapperStyle: { zIndex: 10 },
  position: { y: -10 } as { y: number },
};

function formatTooltipTime(epoch: number): string {
  const d = new Date(epoch);
  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())} KST`;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function SeismicTooltip({ active, payload }: TooltipProps<any, any>) {
  if (!active || !payload?.length) return null;
  const point = payload[0]?.payload as { time: number; magnitude: number; place: string; lat: number; lng: number } | undefined;
  if (!point) return null;
  return (
    <div style={{ background: '#1a1a2e', border: '1px solid #333', padding: '4px 8px', borderRadius: 4, fontSize: 10, color: '#e0e0e0' }}>
      <div style={{ color: '#aaa', marginBottom: 2 }}>{formatTooltipTime(point.time)}</div>
      <div><span style={{ color: getMagnitudeColor(point.magnitude), fontWeight: 700 }}>M{point.magnitude.toFixed(1)}</span> {point.place}</div>
      <div style={{ color: '#888', fontSize: 9 }}>{point.lat.toFixed(3)}N, {point.lng.toFixed(3)}E — click to focus</div>
    </div>
  );
}

function getMagnitudeColor(mag: number): string {
  if (mag < 2.5) return MAGNITUDE_COLORS[0];
  if (mag < 3.5) return MAGNITUDE_COLORS[1];
  if (mag < 4.5) return MAGNITUDE_COLORS[2];
  if (mag < 5.5) return MAGNITUDE_COLORS[3];
  return MAGNITUDE_COLORS[4];
}

export function SensorChart({ seismicData, pressureData, currentTime, historyMinutes, onSeismicClick }: Props) {
  const { t } = useTranslation();

  const totalMinutes = historyMinutes * 8;
  const rangeStart = currentTime - totalMinutes * MINUTE;
  const rangeEnd = currentTime;
  // 데이터 수집 범위: 표시 범위보다 충분히 과거 (선이 y축에서 시작되도록)
  // 기압 데이터는 1시간 간격이므로 최소 60분 + 1칸 여유
  const dataStart = rangeStart - Math.max(historyMinutes, 60) * MINUTE;

  const ticks = useMemo(() => buildTicks(currentTime, historyMinutes), [currentTime, historyMinutes]);

  const seismicPoints = useMemo(
    () => prepareSeismicPoints(seismicData, dataStart, rangeEnd),
    [seismicData, dataStart, rangeEnd],
  );

  const pressureMerged = useMemo(
    () => preparePressureMerged(pressureData, dataStart, rangeEnd),
    [pressureData, dataStart, rangeEnd],
  );

  const pressureStations = useMemo(() => {
    const stations = new Set<string>();
    for (const r of pressureData) stations.add(r.station);
    return Array.from(stations);
  }, [pressureData]);

  const noiseChart = useMemo(
    () => generateDemoData(dataStart, rangeEnd, 45, 30),
    [dataStart, rangeEnd],
  );
  const radiationChart = useMemo(
    () => generateDemoData(dataStart, rangeEnd, 0.08, 0.06),
    [dataStart, rangeEnd],
  );

  const commonXAxis = {
    type: 'number' as const,
    domain: [rangeStart, rangeEnd] as [number, number],
    ticks,
    tickFormatter: formatTickTime,
    tick: { fontSize: 9, fill: '#888' },
  };

  // 지진 y축: 데이터가 있으면 0~max+1, 없으면 0~6
  const maxMag = seismicPoints.length > 0
    ? Math.max(...seismicPoints.map(p => p.magnitude))
    : 0;
  const seismicYMax = Math.max(maxMag + 1, 6);

  return (
    <div className="sensor-chart">
      <h3>{t('sensor.title')}</h3>
      <div className="chart-grid">
        {/* 지진파: Scatter (이벤트 점) */}
        <div className="chart-item">
          <h4>
            {t('sensor.seismicActivity')}
            {seismicPoints.length > 0 && (
              <span className="text-[9px] text-kcg-muted ml-1">
                ({seismicPoints.length} events)
              </span>
            )}
          </h4>
          <ResponsiveContainer width="100%" height={80}>
            <ScatterChart>
              <CartesianGrid strokeDasharray="3 3" stroke="#333" />
              <XAxis dataKey="time" {...commonXAxis} />
              <YAxis dataKey="magnitude" domain={[0, seismicYMax]} tick={{ fontSize: 10, fill: '#888' }} name="M" />
              <ZAxis dataKey="magnitude" range={[30, 200]} name="Size" />
              <Tooltip content={<SeismicTooltip />} {...TOOLTIP_STYLE} />
              <Scatter
                data={seismicPoints}
                shape="circle"
                cursor="pointer"
                onClick={(entry) => {
                  if (entry && onSeismicClick) onSeismicClick(entry.lat, entry.lng, entry.magnitude, entry.place);
                }}
              >
                {seismicPoints.map((p, i) => (
                  <Cell key={i} fill={getMagnitudeColor(p.magnitude)} />
                ))}
              </Scatter>
            </ScatterChart>
          </ResponsiveContainer>
        </div>

        {/* 기압: 관측소별 개별 라인 (해수면 보정) */}
        <div className="chart-item">
          <h4>{t('sensor.airPressureHpa')} <span className="text-[8px] text-kcg-muted">(SLP)</span></h4>
          <ResponsiveContainer width="100%" height={80}>
            <LineChart data={pressureMerged}>
              <CartesianGrid strokeDasharray="3 3" stroke="#333" />
              <XAxis dataKey="time" {...commonXAxis} />
              <YAxis domain={['auto', 'auto']} tick={{ fontSize: 10, fill: '#888' }} />
              <Tooltip
                {...TOOLTIP_STYLE}
                labelFormatter={formatTooltipTime}
                formatter={(v: number, name: string) => [v != null ? `${v.toFixed(1)} hPa` : '-', name]}
              />
              {pressureStations.map(station => (
                <Line
                  key={station}
                  dataKey={station}
                  name={station}
                  stroke={STATION_COLORS[station] || '#888'}
                  dot={false}
                  strokeWidth={1.2}
                  connectNulls
                  isAnimationActive={false}
                />
              ))}
            </LineChart>
          </ResponsiveContainer>
        </div>

        <div className="chart-item">
          <h4>
            {t('sensor.noiseLevelDb')}{' '}
            <span className="chart-demo-label">(DEMO)</span>
          </h4>
          <ResponsiveContainer width="100%" height={80}>
            <LineChart data={noiseChart}>
              <CartesianGrid strokeDasharray="3 3" stroke="#333" />
              <XAxis dataKey="time" {...commonXAxis} />
              <YAxis domain={[0, 140]} tick={{ fontSize: 10, fill: '#888' }} />
              <Tooltip
                {...TOOLTIP_STYLE}
                labelFormatter={formatTooltipTime}
                formatter={(v: number) => [v.toFixed(1), 'dB']}
              />
              <Line type="monotone" dataKey="value" stroke="#f97316" dot={false} strokeWidth={1.5} />
            </LineChart>
          </ResponsiveContainer>
        </div>

        <div className="chart-item">
          <h4>
            {t('sensor.radiationUsv')}{' '}
            <span className="chart-demo-label">(DEMO)</span>
          </h4>
          <ResponsiveContainer width="100%" height={80}>
            <LineChart data={radiationChart}>
              <CartesianGrid strokeDasharray="3 3" stroke="#333" />
              <XAxis dataKey="time" {...commonXAxis} />
              <YAxis domain={[0, 0.3]} tick={{ fontSize: 10, fill: '#888' }} />
              <Tooltip
                {...TOOLTIP_STYLE}
                labelFormatter={formatTooltipTime}
                formatter={(v: number) => [v.toFixed(3), 'μSv/h']}
              />
              <Line type="monotone" dataKey="value" stroke="#22c55e" dot={false} strokeWidth={1.5} />
            </LineChart>
          </ResponsiveContainer>
        </div>
      </div>
    </div>
  );
}
