import type { DashboardResponse, RuntimeMode } from "../../shared/api";
import type { ProbeStore } from "../checker/store";

import { formatDuration, jsonResponse, mapCheckResult } from "../helpers";
import { analyzeIncidentSequence, calculateCurrentStreak, type MetricCheckpoint } from "../metrics";
import { validateDashboardWindow, validateRecentLimit } from "../middleware";

export function handleDashboard(url: URL, store: ProbeStore, mode: RuntimeMode): Response {
  const windowResult = validateDashboardWindow(url.searchParams.get("window"), mode);
  if (windowResult instanceof Response) return windowResult;

  const limitResult = validateRecentLimit(url.searchParams.get("recentLimit"), mode);
  if (limitResult instanceof Response) return limitResult;

  const targets = store.getTargets();
  const latestChecksMap = store.getLatestChecksMap();
  const windowStats = store.getAllTargetWindowStats(windowResult.from, windowResult.to);
  const recentSamplesMap = store.getAllRecentSamples(limitResult.recentLimit);
  const incidentStates = groupDashboardIncidentStates(
    store.getDashboardIncidentStates(windowResult.from, windowResult.to),
  );

  let up = 0;
  let down = 0;
  let lastCheckTime: null | string = null;
  let incidents = 0;

  const responseTargets: DashboardResponse["targets"] = targets.map((target) => {
    const latest = latestChecksMap.get(target.id) ?? null;
    const stats = windowStats.get(target.id) ?? { availability: 0, downChecks: 0, totalChecks: 0, upChecks: 0 };
    const recentSamples = recentSamplesMap.get(target.id) ?? [];
    const currentStreak = calculateCurrentStreak(
      recentSamples.map((sample) => ({
        durationMs: sample.duration_ms,
        matched: sample.matched === 1,
        timestamp: sample.timestamp,
      })),
      limitResult.recentLimit,
    );

    if (latest?.matched === 1) {
      up++;
    } else {
      down++;
    }

    if (latest && (!lastCheckTime || latest.timestamp > lastCheckTime)) {
      lastCheckTime = latest.timestamp;
    }

    incidents += analyzeIncidentSequence(
      incidentStates.get(target.id) ?? [],
      windowResult.from,
      windowResult.to,
    ).incidentCount;

    return {
      currentStreak,
      description: target.description,
      group: target.grp,
      id: target.id,
      interval: formatDuration(target.interval_ms),
      latestCheck: latest ? mapCheckResult(latest, target.type) : null,
      name: target.name,
      recentSamples: recentSamples.map((sample) => ({
        durationMs: sample.duration_ms,
        timestamp: sample.timestamp,
        up: sample.matched === 1,
      })),
      stats,
      target: target.target,
      type: target.type,
    };
  });

  const response: DashboardResponse = {
    summary: {
      down,
      incidents,
      lastCheckTime,
      total: targets.length,
      up,
      window: windowResult,
    },
    targets: responseTargets,
  };

  return jsonResponse(response, { mode });
}

function groupDashboardIncidentStates(
  states: Array<{ matched: number; target_id: string; timestamp: string }>,
): Map<string, MetricCheckpoint[]> {
  const result = new Map<string, MetricCheckpoint[]>();
  for (const state of states) {
    const list = result.get(state.target_id) ?? [];
    list.push({ durationMs: null, matched: state.matched === 1, timestamp: state.timestamp });
    result.set(state.target_id, list);
  }
  return result;
}
