"use client";

import { useEffect, useRef, type ReactNode } from "react";
import type { ChartType } from "@enode/core/api/dtos/charts";
import { useTranslation } from "@enode/core/translations/hooks";
import { InfoIcon } from "@enode/ui/feedback/icons";
import type { BuilderStep, StepState } from "./builder-steps";
import { CHART_TYPES, ChartTypeIcon, useChartTypeText } from "./chart-type-meta";
import { ChoiceRow } from "./guided-steps";

// The full builder's accordion: one step open at a time, every other step
// folded into a one-line summary (✓ when filled, – when not needed, its number
// while still missing). An open step shows the chart type's prompt, its picker
// and Continue. After a Save attempt a missing step turns orange with the
// reason. The order is a suggestion — any step opens at any time.

/**
 * Each step's label and the question it asks while open, worded for the chart
 * type. Labels stay the same across the flat types so a coach recognises them;
 * the prompt carries the type's question. Literal `t` calls, so every string is
 * extractable.
 */
export function useStepText() {
  const { t } = useTranslation();
  return {
    label(step: BuilderStep, type: ChartType): string {
      switch (step) {
        case "type":
          return t("Chart type");
        case "metric":
          return type === "correlation" ? t("Two metrics") : t("Metric");
        case "athletes":
          return t("Athletes");
        case "exercises":
          return t("Exercises");
        case "axes":
          return t("Metrics");
        case "profileGroup":
          return t("Profile group");
        case "referenceGroup":
          return t("Reference group");
        case "timeframe":
          return t("Timeframe");
        case "name":
          return t("Name & note");
      }
    },
    prompt(step: BuilderStep, type: ChartType): string {
      switch (step) {
        case "type":
          return t("Which question should the chart answer?");
        case "metric":
          if (type === "ranking") return t("What should athletes be ranked by?");
          if (type === "distribution") return t("Which number's spread do you want to see?");
          if (type === "correlation") return t("Which two numbers might move together?");
          return t("Which number should the trend follow?");
        case "athletes":
          if (type === "ranking") return t("Who should be ranked?");
          if (type === "distribution") return t("Whose sets?");
          if (type === "correlation") return t("Whose sessions?");
          return t("Whose trend do you want to see?");
        case "exercises":
          if (type === "ranking") return t("Ranked in which exercises?");
          if (type === "distribution") return t("Sets from which exercises?");
          return t("In which exercises?");
        case "axes":
          return t("Which metrics make up the shape? 3 to 6 read best.");
        case "profileGroup":
          return t("Who is this profile about?");
        case "referenceGroup":
          return t("Who should they be compared with?");
        case "timeframe":
          return t("Over which period?");
        case "name":
          return t("Optional. Without a name the chart uses the automatic one.");
      }
    },
  };
}

export function StepperList({ children }: { children: ReactNode }) {
  return <ol className="space-y-2">{children}</ol>;
}

export function StepperSection({
  index,
  title,
  state,
  open,
  summary,
  prompt,
  locked = false,
  attention = null,
  continueLabel,
  onToggle,
  onContinue,
  tourTarget,
  children,
}: {
  /** 1-based position, shown while the step is still missing. */
  index: number;
  title: string;
  state: StepState;
  open: boolean;
  /** The folded line: what's picked, or why it's missing / optional. */
  summary: string;
  /** The chart type's question for this step, shown while it's open. */
  prompt: string;
  /** Shown but can't be opened (a saved chart's type). */
  locked?: boolean;
  /** Why Save refused this step (after a Save attempt), else null. */
  attention?: string | null;
  continueLabel: string;
  onToggle: () => void;
  onContinue: () => void;
  tourTarget?: string;
  children: ReactNode;
}) {
  const { t } = useTranslation();
  const ref = useRef<HTMLLIElement>(null);
  // A Save attempt opens the first missing step: bring it into view.
  useEffect(() => {
    if (open && attention) ref.current?.scrollIntoView({ block: "start", behavior: "smooth" });
  }, [open, attention]);

  const missing = state === "todo";
  const frame = attention
    ? "border-feedback-warning bg-feedback-warning-surface"
    : open
      ? "border-foreground-platinum-green-bright bg-surface-base"
      : "border-surface-stroke bg-surface-base";

  const header = (
    <>
      <StepMark index={index} state={state} />
      <span className="min-w-0 flex-1">
        <span className="body-prominent block text-foreground-default">{title}</span>
        <span
          className={`body-small block ${
            open
              ? "text-foreground-default"
              : attention || missing
                ? "text-foreground-red-orange"
                : "truncate text-foreground-muted"
          }`}
        >
          {open ? prompt : (attention ?? summary)}
        </span>
      </span>
      {locked ? (
        <span className="stat-small shrink-0 text-foreground-more-muted">{t("Locked")}</span>
      ) : !open && !missing ? (
        <span className="body-small shrink-0 font-medium text-foreground-red-orange">{t("Edit")}</span>
      ) : null}
    </>
  );

  return (
    <li ref={ref} data-tour={tourTarget} className={`scroll-mt-4 rounded-2xl border transition-colors ${frame}`}>
      {locked ? (
        <div className="flex w-full items-center gap-3 px-4 py-3">{header}</div>
      ) : (
        <button
          type="button"
          onClick={onToggle}
          aria-expanded={open}
          className="flex w-full items-center gap-3 px-4 py-3 text-left"
        >
          {header}
        </button>
      )}
      {open ? (
        <div className="space-y-4 px-4 pb-4">
          {attention ? <p className="body-small font-medium text-feedback-warning">{attention}</p> : null}
          {children}
          <div className="flex justify-end">
            <button
              type="button"
              onClick={onContinue}
              className="clickable-small rounded-full bg-foreground-default px-5 py-2 text-surface-base transition-opacity hover:opacity-90"
            >
              {continueLabel}
            </button>
          </div>
        </div>
      ) : null}
    </li>
  );
}

function StepMark({ index, state }: { index: number; state: StepState }) {
  if (state === "done")
    return (
      <span aria-hidden className="flex size-6 shrink-0 items-center justify-center rounded-full bg-foreground-platinum-green-bright text-xs font-semibold text-white">
        ✓
      </span>
    );
  if (state === "notNeeded")
    return (
      <span aria-hidden className="flex size-6 shrink-0 items-center justify-center rounded-full border border-dashed border-surface-stroke text-xs text-foreground-more-muted">
        –
      </span>
    );
  return (
    <span aria-hidden className="stat-small flex size-6 shrink-0 items-center justify-center rounded-full border-[1.5px] border-surface-stroke text-foreground-default">
      {index}
    </span>
  );
}

/** "2 of 3 required parts done" over a thin bar, or "Ready to save". */
export function StepperProgress({ done, total, ready }: { done: number; total: number; ready: boolean }) {
  const { t } = useTranslation();
  const ratio = ready ? 1 : total > 0 ? done / total : 0;
  return (
    <div>
      <div className="h-1 overflow-hidden rounded-full bg-surface-base-muted">
        <div
          className="h-full rounded-full bg-foreground-platinum-green-bright transition-[width]"
          style={{ width: `${ratio * 100}%` }}
        />
      </div>
      <p className={`body-small mt-1.5 ${ready ? "font-medium text-feedback-success" : "text-foreground-muted"}`} aria-live="polite">
        {ready
          ? t("Ready to save")
          : t("{done} of {total} required parts done", { done, total })}
      </p>
    </div>
  );
}

/** The type step's choices: all five, each with the question it answers. */
export function TypeChoices({
  value,
  onChange,
  onShowWalkthrough,
}: {
  value: ChartType;
  onChange: (type: ChartType) => void;
  onShowWalkthrough: (type: ChartType) => void;
}) {
  const { t } = useTranslation();
  const text = useChartTypeText();
  return (
    <div className="space-y-2" role="radiogroup" aria-label={t("Chart type")}>
      {CHART_TYPES.map((type) => (
        <ChoiceRow
          key={type}
          active={type === value}
          title={text.label(type)}
          detail={text.question(type)}
          leading={<ChartTypeIcon type={type} className="size-4 shrink-0 text-foreground-muted" />}
          onClick={() => onChange(type)}
        />
      ))}
      <HowItWorksLink onClick={() => onShowWalkthrough(value)} />
    </div>
  );
}

function HowItWorksLink({ onClick }: { onClick: () => void }) {
  const { t } = useTranslation();
  return (
    <button
      type="button"
      onClick={onClick}
      className="clickable-small body-small inline-flex items-center gap-1.5 text-foreground-muted transition-colors hover:text-foreground-default"
    >
      <InfoIcon className="size-4" />
      {t("How this chart works")}
    </button>
  );
}

/**
 * The last thing in the builder: the chart built from the picks (or its layout
 * while a step is missing), what it opens as, and a warning where even that
 * view gets hard to read.
 */
export function ResultCard({
  preview,
  status,
  opensAs,
  series = null,
  warning,
  complete,
  onShowWalkthrough,
}: {
  preview: ReactNode;
  /** Where the preview stands, beside the heading ("Building preview…"). */
  status: string;
  /** The view it opens with ("one panel per athlete"), or null while incomplete. */
  opensAs: string | null;
  /** athlete × lift series, when the type has them. */
  series?: number | null;
  warning: string | null;
  complete: boolean;
  /** Opens the chart type's walkthrough; the link is hidden without it. */
  onShowWalkthrough?: () => void;
}) {
  const { t } = useTranslation();
  return (
    <section className="rounded-2xl border border-surface-stroke bg-surface-base-muted/40 p-4">
      <div className="mb-3 flex items-center justify-between gap-3">
        <h3 className="body-small text-foreground-muted">{t("What you'll get")}</h3>
        <span className="stat-small text-foreground-more-muted" aria-live="polite">
          {status}
        </span>
      </div>
      <div className={complete ? undefined : "opacity-45"}>{preview}</div>
      {opensAs ? (
        <p className="body-small mt-3 font-medium text-foreground-default">
          {t("Opens as {view}", { view: opensAs })}
          {series != null ? (
            <span className="font-normal text-foreground-muted">
              {" · "}
              {t("{count, plural, one {# series} other {# series}}", { count: series })}
            </span>
          ) : null}
        </p>
      ) : (
        <p className="body-small mt-3 text-foreground-muted">
          {t("Fill the missing steps to see what it opens as.")}
        </p>
      )}
      {warning ? <p className="body-small mt-1 text-feedback-warning">{warning}</p> : null}
      {onShowWalkthrough ? (
        <div className="mt-2">
          <HowItWorksLink onClick={onShowWalkthrough} />
        </div>
      ) : null}
    </section>
  );
}
