import type {
  DomesticAnswerValue,
  DomesticConditionConfig,
  DomesticConditionType,
  DomesticOptionsConfig,
  DomesticQuestionType,
} from "@/types/participant";

export const FEED_WINDOW = 10;
export const SKIP_COOLDOWN_DAYS = 7;
export const SHORT_TEXT_MAX = 500;

export const DOMESTIC_TYPE_LABELS: Record<DomesticQuestionType, string> = {
  single_choice: "Single choice",
  multi_choice: "Multiple choice",
  yes_no: "Yes / No",
  rating: "Rating",
  number: "Number",
  short_text: "Short text",
};

export const CONDITION_LABELS: Record<DomesticConditionType, string> = {
  always: "Always",
  equals: "Answer equals",
  not_equals: "Answer is not",
  any_of: "Answer is any of",
  includes: "Selection includes",
  gte: "Answer ≥",
  lte: "Answer ≤",
};

export const EDGE_TYPE_LABELS = {
  unlock: "Unlock next",
  boost: "Boost priority",
  suppress: "Suppress",
  terminate: "Stop branch",
} as const;

const CONDITIONS_BY_TYPE: Record<DomesticQuestionType, DomesticConditionType[]> = {
  single_choice: ["always", "equals", "not_equals", "any_of"],
  multi_choice: ["always", "includes", "any_of"],
  yes_no: ["always", "equals", "not_equals"],
  rating: ["always", "equals", "not_equals", "gte", "lte"],
  number: ["always", "equals", "not_equals", "gte", "lte"],
  short_text: ["always"],
};

export function conditionsForType(
  type: DomesticQuestionType
): DomesticConditionType[] {
  return CONDITIONS_BY_TYPE[type];
}

export function isChoiceType(type: DomesticQuestionType) {
  return type === "single_choice" || type === "multi_choice";
}

export function optionValuesFor(
  type: DomesticQuestionType,
  config: DomesticOptionsConfig | null
): string[] {
  if (type === "yes_no") return ["yes", "no"];
  return (config?.options ?? []).map((o) => o.value);
}

export function ratingRange(config: DomesticOptionsConfig | null) {
  const min = Number.isInteger(config?.min) ? (config!.min as number) : 1;
  const max = Number.isInteger(config?.max) ? (config!.max as number) : 5;
  return { min, max: Math.max(min + 1, max) };
}

type ValidationResult =
  | { ok: true; value: DomesticAnswerValue }
  | { ok: false; error: string };

/** Server-side answer validation against the exact version answered. */
export function validateDomesticAnswer(
  type: DomesticQuestionType,
  config: DomesticOptionsConfig | null,
  raw: unknown
): ValidationResult {
  switch (type) {
    case "single_choice":
    case "yes_no": {
      const allowed = optionValuesFor(type, config);
      if (typeof raw !== "string" || !allowed.includes(raw)) {
        return { ok: false, error: "Choose one of the options" };
      }
      return { ok: true, value: raw };
    }
    case "multi_choice": {
      const allowed = new Set(optionValuesFor(type, config));
      if (!Array.isArray(raw) || raw.length === 0) {
        return { ok: false, error: "Choose at least one option" };
      }
      const unique = Array.from(new Set(raw));
      if (!unique.every((v) => typeof v === "string" && allowed.has(v))) {
        return { ok: false, error: "Invalid selection" };
      }
      return { ok: true, value: unique as string[] };
    }
    case "rating": {
      const { min, max } = ratingRange(config);
      const n = typeof raw === "number" ? raw : Number(raw);
      if (!Number.isInteger(n) || n < min || n > max) {
        return { ok: false, error: `Choose a rating from ${min} to ${max}` };
      }
      return { ok: true, value: n };
    }
    case "number": {
      const n = typeof raw === "number" ? raw : Number(raw);
      if (raw === "" || raw == null || !Number.isFinite(n)) {
        return { ok: false, error: "Enter a number" };
      }
      if (config?.min != null && n < config.min) {
        return { ok: false, error: `Minimum is ${config.min}` };
      }
      if (config?.max != null && n > config.max) {
        return { ok: false, error: `Maximum is ${config.max}` };
      }
      return { ok: true, value: n };
    }
    case "short_text": {
      if (typeof raw !== "string" || !raw.trim()) {
        return { ok: false, error: "Enter an answer" };
      }
      const text = raw.trim();
      if (text.length > SHORT_TEXT_MAX) {
        return { ok: false, error: `Keep it under ${SHORT_TEXT_MAX} characters` };
      }
      return { ok: true, value: text };
    }
    default:
      return { ok: false, error: "Unsupported question type" };
  }
}

function same(a: unknown, b: unknown) {
  return String(a) === String(b);
}

/** Deterministic edge condition evaluation. */
export function evaluateCondition(
  conditionType: DomesticConditionType,
  config: DomesticConditionConfig | null,
  value: unknown
): boolean {
  const values = Array.isArray(value) ? value : [value];
  switch (conditionType) {
    case "always":
      return true;
    case "equals":
      return values.some((v) => same(v, config?.value));
    case "not_equals":
      return !values.some((v) => same(v, config?.value));
    case "any_of": {
      const targets = config?.values ?? [];
      return values.some((v) => targets.some((t) => same(v, t)));
    }
    case "includes":
      return values.some((v) => same(v, config?.value));
    case "gte":
      return Number(value) >= Number(config?.value);
    case "lte":
      return Number(value) <= Number(config?.value);
    default:
      return false;
  }
}

/** Human readable answer for history/admin views. */
export function formatDomesticAnswer(
  type: DomesticQuestionType,
  config: DomesticOptionsConfig | null,
  value: unknown
): string {
  if (value == null) return "—";
  const labelFor = (v: unknown) => {
    if (type === "yes_no") return v === "yes" ? "Yes" : v === "no" ? "No" : String(v);
    const opt = config?.options?.find((o) => o.value === v);
    return opt?.label ?? String(v);
  };
  if (Array.isArray(value)) return value.map(labelFor).join(", ");
  if (type === "rating") {
    const { max } = ratingRange(config);
    return `${value} / ${max}`;
  }
  return labelFor(value);
}
