import { DateTime } from 'luxon';

import type { ChlorinationReportDataBlock } from '../clorination/chlorinationReport';

const PRESSURE_MIN = 7;
const PRESSURE_MAX = 11;

function clamp(n: number, lo: number, hi: number): number {
  return Math.min(hi, Math.max(lo, n));
}

/**
 * Generates `count` pressure readings in [7.3, 11.0] with small step-to-step variation,
 * avoiding near-duplicate consecutive values. Returns formatted numeric strings (one decimal).
 */
export function generatePressureValues(count: number, rng: () => number = Math.random): string[] {
  if (count <= 0) return [];

  const lo = PRESSURE_MIN;
  const hi = PRESSURE_MAX;

  const raw: number[] = [];
  let cur = lo + rng() * (hi - lo);

  for (let i = 0; i < count; i++) {
    if (i > 0) {
      const maxStep = Math.min(0.85, (hi - lo) * 0.35);
      const step = (rng() - 0.5) * 2 * maxStep;
      cur = clamp(cur + step, lo, hi);
      const prev = raw[i - 1]!;
      if (Math.abs(cur - prev) < 0.08) {
        const bump = (rng() - 0.5) * Math.min(0.5, hi - lo);
        cur = clamp(cur + bump, lo, hi);
      }
    }
    raw.push(cur);
  }

  return raw.map((v) => {
    const rounded = Math.round(v * 10) / 10;
    const clamped = clamp(rounded, PRESSURE_MIN, PRESSURE_MAX);
    return clamped.toFixed(1);
  });
}

export type PressureRemarkEntry = { dateIso: string; remark: string };

const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
const REMARK_MAX_LEN = 200;

function sanitizeRemark(raw: unknown): string {
  return String(raw ?? '')
    .replace(/\s+/g, ' ')
    .trim()
    .slice(0, REMARK_MAX_LEN);
}

/** Parse date-wise pressure remarks from JSON (FormData string or array). */
export function parsePressureRemarksPayload(raw: unknown): PressureRemarkEntry[] {
  let parsed: unknown = raw;
  if (typeof raw === 'string') {
    const trimmed = raw.trim();
    if (!trimmed) return [];
    try {
      parsed = JSON.parse(trimmed);
    } catch {
      return [];
    }
  }
  if (!Array.isArray(parsed)) return [];

  const byDate = new Map<string, string>();
  for (const item of parsed) {
    if (!item || typeof item !== 'object') continue;
    const rec = item as { date?: unknown; dateIso?: unknown; remark?: unknown };
    const dateIso = String(rec.date ?? rec.dateIso ?? '')
      .trim()
      .slice(0, 10);
    if (!ISO_DATE.test(dateIso)) continue;
    byDate.set(dateIso, sanitizeRemark(rec.remark));
  }

  return [...byDate.entries()]
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([dateIso, remark]) => ({ dateIso, remark }));
}

/** Measurement dates from remark entries that fall in the inclusive bill period. */
export function measurementDatesFromPressureRemarks(
  entries: PressureRemarkEntry[],
  from: DateTime,
  to: DateTime,
  zone: string
): DateTime[] {
  const start = from.setZone(zone).startOf('day');
  const end = to.setZone(zone).startOf('day');
  if (!start.isValid || !end.isValid || start > end) return [];

  const out: DateTime[] = [];
  for (const entry of entries) {
    const dt = DateTime.fromISO(entry.dateIso, { zone }).startOf('day');
    if (!dt.isValid || dt < start || dt > end) continue;
    out.push(dt);
  }
  return out;
}

export function buildConsumerEndPressureReportData(params: {
  measurementDates: DateTime[];
  villageNames: string[];
  timezone: string;
  rng?: () => number;
  remarksByDateIso?: Record<string, string>;
}): ChlorinationReportDataBlock[] {
  const { measurementDates, villageNames, timezone, rng = Math.random, remarksByDateIso = {} } = params;
  const random = rng;
  const reportData: ChlorinationReportDataBlock[] = [];
  let sNo = 1;

  for (const dt of measurementDates) {
    const zoned = dt.setZone(timezone);
    const dateStr = zoned.toFormat('dd/LL/yyyy');
    const dateIso = zoned.toISODate() || '';
    const pressureStrings = generatePressureValues(villageNames.length, random);
    const habitations = villageNames.map((name, idx) => ({
      name,
      value: pressureStrings[idx] ?? '—',
    }));
    reportData.push({
      sNo: sNo++,
      date: dateStr,
      remark: remarksByDateIso[dateIso] || '',
      habitations,
    });
  }

  return reportData;
}
