'use client'

// Cost bridge / waterfall (KAR-840, V11 section 2 — buildBridgeSummary).
// ALT quotation price → one floating step per metric delta (red = teurer,
// green = günstiger) → NEU price as a stacked bucket composition. Stacking
// trick: a transparent 'base' bar lifts each step to its running level.
// Bucket/stand colors are the V11 constants, registered as CSS vars.

import {
  Bar,
  BarChart,
  CartesianGrid,
  Cell,
  LabelList,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts'
import { BUCKET_LABEL_DE, type BridgeData } from '@/lib/qaf-differences'
import { moneyFormatter } from './format'

const BUCKET_FILL: Record<string, string> = {
  Material: 'var(--qaf-bucket-material)',
  Labor: 'var(--qaf-bucket-labor)',
  Manufacturing: 'var(--qaf-bucket-manufacturing)',
  FWZ: 'var(--qaf-bucket-fwz)',
  ScrapB: 'var(--qaf-bucket-scrap)',
  SGA: 'var(--qaf-bucket-sga)',
  Profit: 'var(--qaf-bucket-profit)',
  Other: 'var(--qaf-bucket-other)',
}

export interface WaterfallRow {
  name: string
  /** Row role — the tooltip must never guess ALT vs NEU from value signs. */
  kind: 'alt' | 'step' | 'end'
  /** Transparent offset lifting a step to its running level. */
  base: number
  /** Positive step (teurer, red). */
  increase: number
  /** Negative step magnitude (günstiger, green). */
  decrease: number
  /** ALT anchor bar. */
  total: number
  /** Solid NEU bar — fallback when the composition is not stackable. */
  neuTotal: number
  /** Annotation value for step rows (signed). */
  delta: number | null
  /** Bucket the step feeds (tooltip context), null for anchor/end rows. */
  bucketLabel: string | null
  // NEU composition (only on the last row)
  Material: number
  Labor: number
  Manufacturing: number
  FWZ: number
  ScrapB: number
  SGA: number
  Profit: number
  Other: number
}

function emptyRow(name: string, kind: WaterfallRow['kind'] = 'step'): WaterfallRow {
  return {
    name,
    kind,
    base: 0,
    increase: 0,
    decrease: 0,
    total: 0,
    neuTotal: 0,
    delta: null,
    bucketLabel: null,
    Material: 0,
    Labor: 0,
    Manufacturing: 0,
    FWZ: 0,
    ScrapB: 0,
    SGA: 0,
    Profit: 0,
    Other: 0,
  }
}

/** Pure waterfall layout: running-level offsets for the floating steps. */
export function buildWaterfallData(bridge: BridgeData): WaterfallRow[] {
  const rows: WaterfallRow[] = [{ ...emptyRow('ALT', 'alt'), total: bridge.start }]

  let level = bridge.start
  for (const step of bridge.steps) {
    const row = emptyRow(step.label)
    row.delta = step.delta
    row.bucketLabel = BUCKET_LABEL_DE[step.bucket]
    if (step.delta >= 0) {
      row.base = level
      row.increase = step.delta
    } else {
      row.base = level + step.delta
      row.decrease = -step.delta
    }
    level += step.delta
    rows.push(row)
  }

  const end = emptyRow('NEU', 'end')
  if (bridge.endComposition.length > 0) {
    for (const part of bridge.endComposition) {
      end[part.key] = part.value
    }
  } else {
    // Composition not stackable (a part would be negative) — solid NEU bar.
    end.neuTotal = bridge.end
  }
  rows.push(end)
  return rows
}

const deltaFmt = new Intl.NumberFormat('de-DE', { maximumFractionDigits: 2, signDisplay: 'exceptZero' })

// Rendered per series: the label must sit on the VISIBLE bar of its row —
// increases live on the 'increase' bar, decreases on the 'decrease' bar
// (LabelList reads its geometry from the bar it is attached to).
function StepLabel(props: {
  x?: number | string
  y?: number | string
  width?: number | string
  index?: number
  rows: WaterfallRow[]
  series: 'increase' | 'decrease'
}) {
  const { x, y, width, index, rows, series } = props
  if (index === undefined || x === undefined || y === undefined || width === undefined) return null
  const delta = rows[index]?.delta
  if (delta === null || delta === undefined) return null
  if (series === 'increase' ? delta <= 0 : delta >= 0) return null
  return (
    <text
      x={Number(x) + Number(width) / 2}
      y={Number(y) - 6}
      textAnchor="middle"
      fontSize={11}
      fontWeight={600}
      fill={delta > 0 ? 'var(--destructive)' : 'var(--success-text)'}
    >
      {deltaFmt.format(delta)}
    </text>
  )
}

// NEU total annotation — attached to whichever bar tops the end stack.
function EndLabel(props: {
  x?: number | string
  y?: number | string
  width?: number | string
  index?: number
  lastIndex: number
  text: string
}) {
  const { x, y, width, index, lastIndex, text } = props
  if (index !== lastIndex || x === undefined || y === undefined || width === undefined) return null
  return (
    <text
      x={Number(x) + Number(width) / 2}
      y={Number(y) - 6}
      textAnchor="middle"
      fontSize={11}
      fontWeight={600}
      fill="var(--foreground)"
    >
      {text}
    </text>
  )
}

interface Props {
  bridge: BridgeData
  currency: string | null
}

export default function QafBridgeChart({ bridge, currency }: Props) {
  const rows = buildWaterfallData(bridge)
  const fmt = moneyFormatter(currency)
  const lastIndex = rows.length - 1
  const endLabelText = `${fmt(bridge.end)} (Δ ${deltaFmt.format(bridge.delta)})`
  // Only the buckets actually present in this bridge render as bars — a
  // summary bridge must not grow zero-valued Labor/Profit tooltip lines.
  const compositionKeys = bridge.endComposition.map((p) => p.key)
  // The NEU total label must sit on the TOPMOST non-zero bar of the end row —
  // 'Other' can legitimately be 0 (G60 without logistics remainder).
  const endRow = rows[lastIndex]
  const topEndKey =
    [...compositionKeys].reverse().find((k) => Math.abs(endRow[k]) > 0.00005) ?? 'neuTotal'

  return (
    <div className="h-80 w-full" data-testid="qaf-bridge-chart">
      <ResponsiveContainer width="100%" height="100%">
        <BarChart data={rows} margin={{ top: 24, right: 8, left: 8, bottom: 4 }} barCategoryGap="18%">
          <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" vertical={false} />
          <XAxis
            dataKey="name"
            interval={0}
            tick={{ fontSize: 10 }}
            tickLine={false}
            angle={-22}
            textAnchor="end"
            height={64}
            axisLine={{ stroke: 'var(--border)' }}
          />
          <YAxis
            tick={{ fontSize: 11 }}
            tickLine={false}
            axisLine={false}
            tickFormatter={(v: number) => fmt(v)}
            width={82}
          />
          <Tooltip
            // Custom content (Kais feedback 05.07.): the default payload listed
            // every series of the category as 0,00 € — show only what the
            // hovered column actually means.
            content={({ active, payload, label }) => {
              if (!active || !payload?.length) return null
              const row = payload[0]?.payload as WaterfallRow | undefined
              if (!row) return null
              const box = 'rounded border border-border bg-card px-3 py-2 text-xs shadow-sm'
              if (row.kind === 'step' && row.delta !== null) {
                const after = row.delta >= 0 ? row.base + row.increase : row.base
                return (
                  <div className={box}>
                    <div className="font-medium text-foreground">
                      {String(label)}
                      {row.bucketLabel ? ` · Bucket: ${row.bucketLabel}` : ''}
                    </div>
                    <div style={{ color: row.delta > 0 ? 'var(--destructive)' : 'var(--success-text)' }}>
                      Δ {row.delta > 0 ? 'teurer' : 'günstiger'}: {deltaFmt.format(row.delta)}
                    </div>
                    <div className="text-muted-foreground">Zwischenstand: {fmt(after)}</div>
                  </div>
                )
              }
              if (row.kind === 'alt') {
                return (
                  <div className={box}>
                    <div className="font-medium text-foreground">ALT (Angebotspreis)</div>
                    <div className="text-muted-foreground">{fmt(bridge.start)}</div>
                  </div>
                )
              }
              const parts = bridge.endComposition.filter((c) => Math.abs(c.value) > 0.00005)
              return (
                <div className={box}>
                  <div className="font-medium text-foreground">NEU (Angebotspreis)</div>
                  <div className="text-muted-foreground">
                    {fmt(bridge.end)} · Δ zu ALT: {deltaFmt.format(bridge.delta)}
                  </div>
                  {parts.map((c) => (
                    <div key={c.key} className="text-muted-foreground">
                      {c.label}: {fmt(c.value)}
                    </div>
                  ))}
                </div>
              )
            }}
            cursor={{ fill: 'var(--muted)' }}
          />
          {/* invisible offset */}
          <Bar dataKey="base" stackId="w" fill="transparent" isAnimationActive={false} />
          {/* ALT anchor */}
          <Bar dataKey="total" name="ALT (Angebotspreis)" stackId="w" fill="var(--qaf-stand-alt)" isAnimationActive={false}>
            <LabelList
              content={(p) => {
                const { x, y, width, index } = p as { x?: number; y?: number; width?: number; index?: number }
                if (index !== 0 || x === undefined || y === undefined || width === undefined) return null
                return (
                  <text x={Number(x) + Number(width) / 2} y={Number(y) - 6} textAnchor="middle" fontSize={11} fontWeight={600} fill="var(--foreground)">
                    {fmt(rows[0].total)}
                  </text>
                )
              }}
            />
          </Bar>
          {/* floating steps — the Δ label sits on the visible bar of its row */}
          <Bar dataKey="increase" stackId="w" isAnimationActive={false}>
            {rows.map((r, i) => (
              <Cell key={i} fill={r.increase > 0 ? 'var(--destructive)' : 'transparent'} />
            ))}
            <LabelList content={(p) => <StepLabel {...(p as object)} rows={rows} series="increase" />} />
          </Bar>
          <Bar dataKey="decrease" stackId="w" isAnimationActive={false}>
            {rows.map((r, i) => (
              <Cell key={i} fill={r.decrease > 0 ? 'var(--success-text)' : 'transparent'} />
            ))}
            <LabelList content={(p) => <StepLabel {...(p as object)} rows={rows} series="decrease" />} />
          </Bar>
          {/* NEU — stacked composition, or a solid bar when not stackable */}
          <Bar dataKey="neuTotal" name="NEU (Angebotspreis)" stackId="w" fill="var(--qaf-stand-neu)" isAnimationActive={false}>
            {topEndKey === 'neuTotal' && <LabelList content={(p) => <EndLabel {...(p as object)} lastIndex={lastIndex} text={endLabelText} />} />}
          </Bar>
          {compositionKeys.map((key) => (
            <Bar key={key} dataKey={key} name={BUCKET_LABEL_DE[key]} stackId="w" fill={BUCKET_FILL[key]} isAnimationActive={false}>
              {key === topEndKey && (
                <LabelList content={(p) => <EndLabel {...(p as object)} lastIndex={lastIndex} text={endLabelText} />} />
              )}
            </Bar>
          ))}
        </BarChart>
      </ResponsiveContainer>
    </div>
  )
}
