/**
 * Savings / yield model behind the bento grid.
 *
 * Deliberately transparent and all in one place: every assumption below is a
 * named constant so the numbers can be re-pointed at a real tariff table or a
 * regional irradiance dataset without touching the UI.
 */

/** Swap this (and RATE_PER_KWH / COST_PER_KW) to localise the whole page. */
export const CURRENCY = "₹";

const RATE_PER_KWH = 8; // ₹/kWh, typical residential slab
const COST_PER_KW = 60000; // ₹/kW installed, before subsidy
const PANEL_WATTS = 450;
const PANEL_SQFT = 18;
const ROOF_USABLE_FRACTION = 0.75; // setbacks, vents, shading
const SYSTEM_EFFICIENCY = 0.85; // inverter + wiring + soiling losses
const ANNUAL_DEGRADATION = 0.005; // 0.5%/yr
const CO2_PER_KWH = 0.71; // kg avoided per kWh on the coal-heavy Indian grid
const TREE_CO2_PER_YEAR = 21; // kg absorbed by one mature tree

/**
 * PM Surya Ghar rooftop subsidy: ₹30,000/kW for the first 2 kW plus ₹18,000
 * for the third, hard-capped at ₹78,000. It is a flat amount rather than a
 * percentage, so a large array claims exactly the same cap as a 3 kW one —
 * which is why payback lengthens rather than shortens as the system grows.
 */
function subsidyFor(systemKw: number): number {
  const firstTwo = Math.min(systemKw, 2) * 30000;
  const third = Math.min(Math.max(systemKw - 2, 0), 1) * 18000;
  return Math.min(firstTwo + third, 78000);
}

export type Exposure = "excellent" | "good" | "partial";

/**
 * Labels answer the question in the control's heading ("How much shade does
 * your roof get?"), so they stay short enough to read at a glance in a narrow
 * three-up segment and the progression is obvious without solar vocabulary.
 */
export const EXPOSURES: { id: Exposure; label: string; sunHours: number }[] = [
  { id: "excellent", label: "None", sunHours: 5.5 },
  { id: "good", label: "Some", sunHours: 4.6 },
  { id: "partial", label: "A lot", sunHours: 3.8 },
];

/** Relative monthly output — normalised so the twelve months average to 1. */
const SEASONAL = [
  // India peaks pre-monsoon (Mar–May), dips hard through the monsoon cloud
  // cover (Jul–Aug) and holds a mild winter floor — not a temperate curve.
  0.92, 1.02, 1.12, 1.15, 1.1, 0.92, 0.78, 0.78, 0.9, 0.98, 0.94, 0.89,
];
const SEASONAL_MEAN = SEASONAL.reduce((a, b) => a + b, 0) / SEASONAL.length;

export type SavingsInput = {
  monthlyBill: number;
  roofArea: number;
  exposure: Exposure;
};

export type SavingsResult = {
  panels: number;
  systemKw: number;
  annualYield: number;
  annualSavings: number;
  monthlySavings: number;
  grossCost: number;
  subsidy: number;
  netCost: number;
  paybackYears: number;
  lifetimeSavings: number;
  co2Tonnes: number;
  trees: number;
  billOffset: number;
  roofUsedPct: number;
  monthlyYield: number[];
  roofLimited: boolean;
};

export function calculateSavings({
  monthlyBill,
  roofArea,
  exposure,
}: SavingsInput): SavingsResult {
  const sunHours =
    EXPOSURES.find((e) => e.id === exposure)?.sunHours ??
    EXPOSURES[1].sunHours;

  const annualKwhUsed = (monthlyBill * 12) / RATE_PER_KWH;
  const kwhPerKwPerYear = sunHours * 365 * SYSTEM_EFFICIENCY;

  // Panels needed to cover consumption, then clamped by what the roof holds.
  const panelsForUsage = Math.ceil(
    (annualKwhUsed / kwhPerKwPerYear) * (1000 / PANEL_WATTS),
  );
  const panelsRoofHolds = Math.floor(
    (roofArea * ROOF_USABLE_FRACTION) / PANEL_SQFT,
  );
  const panels = Math.max(1, Math.min(panelsForUsage, panelsRoofHolds));
  const roofLimited = panelsForUsage > panelsRoofHolds;

  const systemKw = (panels * PANEL_WATTS) / 1000;
  const annualYield = systemKw * kwhPerKwPerYear;

  // Self-consumption is worth full retail; anything beyond the bill is export.
  const offsetKwh = Math.min(annualYield, annualKwhUsed);
  const exportKwh = Math.max(0, annualYield - annualKwhUsed);
  const annualSavings = offsetKwh * RATE_PER_KWH + exportKwh * RATE_PER_KWH * 0.4;

  const grossCost = systemKw * COST_PER_KW;
  const subsidy = subsidyFor(systemKw);
  const netCost = Math.max(0, grossCost - subsidy);
  const paybackYears = annualSavings > 0 ? netCost / annualSavings : 0;

  // 25 years of output with linear panel degradation applied.
  let lifetimeGross = 0;
  for (let year = 0; year < 25; year++) {
    lifetimeGross += annualSavings * (1 - ANNUAL_DEGRADATION * year);
  }

  return {
    panels,
    systemKw,
    annualYield,
    annualSavings,
    monthlySavings: annualSavings / 12,
    grossCost,
    subsidy,
    netCost,
    paybackYears,
    lifetimeSavings: lifetimeGross - netCost,
    co2Tonnes: (annualYield * CO2_PER_KWH * 25) / 1000,
    trees: Math.round((annualYield * CO2_PER_KWH) / TREE_CO2_PER_YEAR),
    billOffset: Math.min(100, (annualYield / annualKwhUsed) * 100),
    roofUsedPct: Math.min(100, ((panels * PANEL_SQFT) / roofArea) * 100),
    monthlyYield: SEASONAL.map((s) => (annualYield / 12) * (s / SEASONAL_MEAN)),
    roofLimited,
  };
}

export function formatCurrency(value: number, compact = false): string {
  const v = Math.round(value);
  // Compact form uses the Indian scale — lakh and crore, not thousands —
  // because ₹12.4L reads instantly here where ₹1,240k does not.
  if (compact) {
    if (v >= 10000000) return `${CURRENCY}${(v / 10000000).toFixed(2)} Cr`;
    if (v >= 100000) return `${CURRENCY}${(v / 100000).toFixed(1)} L`;
    if (v >= 1000) return `${CURRENCY}${Math.round(v / 1000)}k`;
  }
  // en-IN groups as 1,23,456 rather than 123,456.
  return `${CURRENCY}${v.toLocaleString("en-IN")}`;
}

export function formatNumber(value: number, digits = 0): string {
  return value.toLocaleString("en-IN", {
    minimumFractionDigits: digits,
    maximumFractionDigits: digits,
  });
}
