import { Paper, Skeleton, Stack, Table, Text, Title } from '@mantine/core'
import type { Metrics } from '../types'
import { HelpTip } from './HelpTip'

interface Props {
  metrics: Metrics | null
}

function fmt(v: number, digits = 3): string {
  if (!Number.isFinite(v)) return '—'
  if (Math.abs(v) !== 0 && (Math.abs(v) < 1e-2 || Math.abs(v) >= 1e4)) {
    return v.toExponential(2)
  }
  return v.toFixed(digits)
}

const TIPS = {
  zh: (
    <>
      Equivalent reflectivity factor at horizontal polarization (dBZ). In
      the Rayleigh limit it is proportional to the sixth moment of the
      drop-size distribution; at C/X and for hail the full T-matrix
      solution deviates from the D⁶ law due to Mie resonances.
    </>
  ),
  zv: (
    <>
      Equivalent reflectivity factor at vertical polarization (dBZ). For
      oblate particles Z<sub>v</sub> &lt; Z<sub>h</sub> because the
      vertical axis is shorter than the horizontal.
    </>
  ),
  zdr: (
    <>
      Differential reflectivity, 10·log₁₀(Z<sub>h</sub>/Z<sub>v</sub>) in
      dB. Positive for horizontally-oriented oblate particles (large rain
      drops, aggregates), near zero for spheres (small rain, hail
      tumbling), negative for vertically-aligned prolate shapes
      (conical graupel, some crystals).
    </>
  ),
  ldr: (
    <>
      Linear depolarization ratio (dB) — ratio of cross-polar to co-polar
      return when transmitting one polarization. Elevated by canting,
      irregular or mixed-phase particles. Spheres with zero canting give
      LDR → −∞.
    </>
  ),
  rhohv: (
    <>
      Co-polar correlation coefficient between H and V returns. Close to 1
      for uniform populations; depressed by size, shape, or phase
      diversity — useful for detecting mixed-phase layers, debris, and
      non-meteorological targets.
    </>
  ),
  delta: (
    <>
      Backscatter differential phase shift (°). Non-zero when scattering
      is in the Mie regime — e.g., large drops at C/X band, wet hail.
      Contaminates Φ<sub>DP</sub> and can bias K<sub>dp</sub> estimates
      if not removed.
    </>
  ),
  kdp: (
    <>
      Specific differential phase (° km⁻¹) — propagation-based, half the
      range derivative of Φ<sub>DP</sub>. Proportional to the product of
      water content and drop oblateness. Immune to attenuation and
      calibration biases; the workhorse for rainfall estimation in heavy
      rain.
    </>
  ),
  ah: (
    <>
      Specific attenuation at horizontal polarization (dB km⁻¹). Small at
      S band, significant at C and X. K<sub>dp</sub>-based attenuation
      correction (e.g., ZPHI) relies on the near-linear A<sub>h</sub>–
      K<sub>dp</sub> relationship.
    </>
  ),
  adr: (
    <>
      Specific differential attenuation (dB km⁻¹) — A<sub>h</sub> minus
      A<sub>v</sub>. Biases Z<sub>dr</sub> in heavy-rain paths at C/X;
      commonly corrected using A<sub>dr</sub> ∝ K<sub>dp</sub>.
    </>
  ),
  nt: (
    <>
      Total number concentration (m⁻³) — the zeroth moment of the PSD,
      ∫N(D) dD. Equals the area under the PSD curve (in linear, not
      log, space).
    </>
  ),
  lwc: (
    <>
      Liquid (or ice-mass-equivalent) water content (g m⁻³) — third
      moment of the PSD weighted by hydrometeor density. For snow
      presets this is the ice-mass content using the habit-specific
      ρ(D).
    </>
  ),
}

export function MetricsTable({ metrics }: Props) {
  const rows: Array<[React.ReactNode, string, React.ReactNode]> = metrics
    ? [
        [<>Z<sub>h</sub> (dBZ)</>, fmt(metrics.zh_dbz, 2), TIPS.zh],
        [<>Z<sub>v</sub> (dBZ)</>, fmt(metrics.zv_dbz, 2), TIPS.zv],
        [<>Z<sub>dr</sub> (dB)</>, fmt(metrics.zdr_db, 3), TIPS.zdr],
        ['LDR (dB)', fmt(metrics.ldr_db, 2), TIPS.ldr],
        [<>ρ<sub>hv</sub></>, fmt(metrics.rho_hv, 5), TIPS.rhohv],
        [<>δ<sub>hv</sub> (deg)</>, fmt(metrics.delta_deg, 3), TIPS.delta],
        [<>K<sub>dp</sub> (° km⁻¹)</>, fmt(metrics.kdp_deg_per_km, 4), TIPS.kdp],
        [<>A<sub>h</sub> (dB km⁻¹)</>, fmt(metrics.ah_db_per_km, 4), TIPS.ah],
        [<>A<sub>dr</sub> (dB km⁻¹)</>, fmt(metrics.adr_db_per_km, 5), TIPS.adr],
        [<>N<sub>T</sub> (m⁻³)</>, fmt(metrics.nt_per_m3, 2), TIPS.nt],
        ['LWC (g m⁻³)', fmt(metrics.lwc_g_per_m3, 4), TIPS.lwc],
      ]
    : []

  return (
    <Paper withBorder p="md" radius="md" shadow="xs">
      <Title order={4} mb="sm">
        T-matrix scattering results
      </Title>
      {metrics ? (
        <Table striped highlightOnHover withRowBorders={false} verticalSpacing={6}>
          <Table.Tbody>
            {rows.map(([label, v, tip], i) => (
              <Table.Tr key={i}>
                <Table.Td style={{ width: '55%' }}>
                  <Text size="sm" component="span">
                    {label}
                    <HelpTip label={tip} />
                  </Text>
                </Table.Td>
                <Table.Td>
                  <Text size="sm" fw={600} ff="monospace">
                    {v}
                  </Text>
                </Table.Td>
              </Table.Tr>
            ))}
          </Table.Tbody>
        </Table>
      ) : (
        <Stack gap="xs">
          {Array.from({ length: 8 }).map((_, i) => (
            <Skeleton key={i} height={20} radius="sm" />
          ))}
        </Stack>
      )}
    </Paper>
  )
}
