import type { BrandPulse, Initiative, SocialRange, SocialSnapshot } from "@/lib/marketing/types";

export type DepartmentScoreBreakdown = {
  total: number;
  initiatives: number;
  social: number;
  brand: number;
};

export type DepartmentScoreInput = {
  initiatives: Initiative[];
  socialSnapshots: SocialSnapshot[];
  brandPulse: BrandPulse;
  socialRange?: SocialRange;
};

function clamp(value: number, min: number, max: number): number {
  return Math.min(Math.max(value, min), max);
}

function roundToOne(value: number): number {
  return Math.round(value * 10) / 10;
}

function safePercent(actual: number, target: number): number {
  if (target <= 0) {
    return 0;
  }
  return (actual / target) * 100;
}

function normalizeResultScore(actual: number, target: number): number {
  const capped = clamp(safePercent(actual, target), 0, 120);
  return (capped / 120) * 100;
}

function resolvedActual(manual: number, auto?: number | null): number {
  if (Math.abs(manual) > 0.0001) {
    return manual;
  }

  return typeof auto === "number" && Number.isFinite(auto) ? auto : manual;
}

function weightedAverage(values: Array<{ value: number; weight: number }>): number {
  const totalWeight = values.reduce((acc, item) => acc + item.weight, 0);
  if (totalWeight <= 0) {
    return 0;
  }

  const totalValue = values.reduce((acc, item) => acc + item.value * item.weight, 0);
  return totalValue / totalWeight;
}

function socialSnapshotScore(snapshot: SocialSnapshot): number {
  const growthPercent = safePercent(snapshot.followersEnd - snapshot.followersStart, snapshot.followersStart);
  const growthScore = clamp(((growthPercent + 5) / 15) * 100, 0, 100);
  const engagementScore = clamp((snapshot.engagementRate / 10) * 100, 0, 100);

  return 0.65 * growthScore + 0.35 * engagementScore;
}

export function initiativeScore(initiative: Initiative): number {
  const scoreActual = resolvedActual(initiative.metrics.actual, initiative.autoActual);
  const ticketsActual = resolvedActual(initiative.metrics.ticketsActual, initiative.autoTicketsActual);
  const revenueActual = resolvedActual(initiative.metrics.revenueActual, initiative.autoRevenueActual);
  const resultBuckets: number[] = [];
  if (initiative.metricSelection.score) {
    resultBuckets.push(normalizeResultScore(scoreActual, initiative.metrics.target));
  }
  if (initiative.metricSelection.tickets) {
    resultBuckets.push(normalizeResultScore(ticketsActual, initiative.metrics.ticketsTarget));
  }
  if (initiative.metricSelection.revenue) {
    resultBuckets.push(normalizeResultScore(revenueActual, initiative.metrics.revenueTarget));
  }
  const resultScore =
    resultBuckets.length > 0 ? resultBuckets.reduce((acc, value) => acc + value, 0) / resultBuckets.length : 0;
  const completedOnTime =
    initiative.completedAt !== null && new Date(initiative.completedAt).getTime() <= new Date(initiative.dueDate).getTime();
  const onTimeScore = completedOnTime ? 100 : 70;
  const qualityScore = clamp((initiative.leadRating1to5 / 5) * 100, 0, 100);

  return roundToOne(0.6 * resultScore + 0.2 * onTimeScore + 0.2 * qualityScore);
}

export function departmentScore(input: DepartmentScoreInput): DepartmentScoreBreakdown {
  const initiativesScore = weightedAverage(
    input.initiatives.map((initiative) => ({
      value: initiativeScore(initiative),
      weight: initiative.importanceWeight,
    }))
  );

  const scopedSocialSnapshots = input.socialRange
    ? input.socialSnapshots.filter((snapshot) => snapshot.range === input.socialRange)
    : input.socialSnapshots;
  const socialScore =
    scopedSocialSnapshots.length > 0
      ? scopedSocialSnapshots.reduce((acc, snapshot) => acc + socialSnapshotScore(snapshot), 0) / scopedSocialSnapshots.length
      : 0;

  const brandScore = clamp((input.brandPulse.rating1to5 / 5) * 100, 0, 100);
  const totalScore = 0.5 * initiativesScore + 0.3 * socialScore + 0.2 * brandScore;

  return {
    total: roundToOne(totalScore),
    initiatives: roundToOne(initiativesScore),
    social: roundToOne(socialScore),
    brand: roundToOne(brandScore),
  };
}
