"use client";

import { useEffect, useRef } from "react";
import { CustomPredictionTile } from "@/features/predictions/components/tiles/custom-prediction-tile";
import { LegacyNamesPredictionTile } from "@/features/predictions/components/tiles/legacy-names-prediction-tile";
import { LegacyNumberPredictionTile } from "@/features/predictions/components/tiles/legacy-number-prediction-tile";
import { LegacyPredictionTile } from "@/features/predictions/components/tiles/legacy-prediction-tile";
import { LegacySexPredictionTile } from "@/features/predictions/components/tiles/legacy-sex-prediction-tile";
import { WeightPredictionTile } from "@/features/predictions/components/tiles/weight-prediction-tile";
import type { PredictionTheme } from "@/features/predictions/domain/prediction-theme";
import {
  usePredictionTileController,
  type PredictionTileController,
} from "@/features/predictions/hooks/use-prediction-tile-controller";
import styles from "@/features/predictions/styles/predictions.module.css";
import type { PredictionCard, PredictionEntry, UpsertPredictionPayload } from "@/types/predictions";

type PredictionCardFactoryProps = {
  card: PredictionCard;
  entry?: PredictionEntry;
  disabled?: boolean;
  showSubmitButton?: boolean;
  theme?: PredictionTheme;
  onSave: (cardId: string, payload: UpsertPredictionPayload) => Promise<PredictionEntry>;
  onController?: (cardId: string, controller: PredictionTileController | null) => void;
  onDirtyChange?: () => void;
  onSexSelect?: (value: string) => void;
};

function resolveTile(
  card: PredictionCard,
  controller: PredictionTileController,
  disabled?: boolean,
  showSubmitButton?: boolean,
  theme?: PredictionTheme,
  onSexSelect?: (value: string) => void,
) {
  if (card.code === "legacy_weight") {
    return (
      <WeightPredictionTile
        card={card}
        controller={controller}
        disabled={disabled}
        showSubmitButton={showSubmitButton}
        theme={theme}
      />
    );
  }

  if (card.code === "legacy_sex") {
    return (
      <LegacySexPredictionTile
        card={card}
        controller={controller}
        disabled={disabled}
        showSubmitButton={showSubmitButton}
        onSelect={onSexSelect}
      />
    );
  }

  if (card.code === "legacy_names") {
    return (
      <LegacyNamesPredictionTile
        card={card}
        controller={controller}
        disabled={disabled}
        showSubmitButton={showSubmitButton}
      />
    );
  }

  if (card.type === "LEGACY" && card.valueType === "NUMBER") {
    return (
      <LegacyNumberPredictionTile
        card={card}
        controller={controller}
        disabled={disabled}
        showSubmitButton={showSubmitButton}
      />
    );
  }

  if (card.type === "LEGACY") {
    return (
      <LegacyPredictionTile
        card={card}
        controller={controller}
        disabled={disabled}
        showSubmitButton={showSubmitButton}
      />
    );
  }

  return (
    <CustomPredictionTile
      card={card}
      controller={controller}
      disabled={disabled}
      showSubmitButton={showSubmitButton}
    />
  );
}

export function PredictionCardFactory({
  card,
  entry,
  disabled,
  showSubmitButton,
  theme,
  onSave,
  onController,
  onDirtyChange,
  onSexSelect,
}: PredictionCardFactoryProps) {
  const controller = usePredictionTileController({
    card,
    entry,
    onSave,
    disabled,
  });

  // Keep a stable ref to always expose the latest controller to the parent
  const controllerRef = useRef(controller);
  controllerRef.current = controller;

  // Use a ref so that changing the inline callback in page.tsx doesn't re-trigger the effect
  const onControllerRef = useRef(onController);
  onControllerRef.current = onController;

  const onDirtyChangeRef = useRef(onDirtyChange);
  onDirtyChangeRef.current = onDirtyChange;

  useEffect(() => {
    controller.resetFromEntry(entry);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [entry]);

  // Register a thin stable proxy so the parent always calls the latest controller
  useEffect(() => {
    const proxy: PredictionTileController = {
      get draftValues() { return controllerRef.current.draftValues; },
      get persistedValues() { return controllerRef.current.persistedValues; },
      get dirty() { return controllerRef.current.dirty; },
      get saving() { return controllerRef.current.saving; },
      get errorMessage() { return controllerRef.current.errorMessage; },
      get successMessage() { return controllerRef.current.successMessage; },
      setText: (...args) => controllerRef.current.setText(...args),
      setNumber: (...args) => controllerRef.current.setNumber(...args),
      setDate: (...args) => controllerRef.current.setDate(...args),
      submit: () => controllerRef.current.submit(),
      resetFromEntry: (...args) => controllerRef.current.resetFromEntry(...args),
    };
    onControllerRef.current?.(card.id, proxy);

    return () => {
      onControllerRef.current?.(card.id, null);
    };
    // Only run on mount/unmount (card.id is stable for a given instance)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [card.id]);

  // Notify parent when dirty state OR draft values change so it can refresh derived state
  useEffect(() => {
    onDirtyChangeRef.current?.();
  }, [controller.dirty, controller.draftValues]);

  const isWeightTile = card.code === "legacy_weight";

  return (
    <div className={`${styles.tileShell} ${isWeightTile ? styles.tileShellWeight : ""}`}>
      {resolveTile(card, controller, disabled, showSubmitButton, theme, onSexSelect)}
    </div>
  );
}
