import { calculateReportScore, getEntryTime } from "./scoring";
import { attachIntegrity, createExportIntegrity, summarizeVerification, verifyEntryIntegrity } from "./integrity";
import type { DelayedFollowup, ExportPayload, FollowupDraft, ImportSummary, Report, ReportDraft, StoredEntry } from "./types";

const STORAGE_KEY = "arbeidsevne-egenvurdering:entries";

function readEntries(): StoredEntry[] {
  const raw = localStorage.getItem(STORAGE_KEY);
  if (!raw) return [];

  try {
    const parsed = JSON.parse(raw);
    const entries = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.reports) ? parsed.reports : [];
    return entries.map(normalizeStoredEntry);
  } catch {
    return [];
  }
}

function writeEntries(entries: StoredEntry[]) {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(entries));
}

function dateParts(now = new Date()) {
  const localDate = [
    now.getFullYear(),
    String(now.getMonth() + 1).padStart(2, "0"),
    String(now.getDate()).padStart(2, "0")
  ].join("-");

  return {
    report_date: localDate,
    report_time: [
      String(now.getHours()).padStart(2, "0"),
      String(now.getMinutes()).padStart(2, "0"),
      String(now.getSeconds()).padStart(2, "0")
    ].join(":")
  };
}

function baseFields() {
  const now = new Date();
  return {
    id: crypto.randomUUID(),
    created_at: now.toISOString(),
    ...dateParts(now)
  };
}

export function createReport(draft: ReportDraft): Report {
  if (
    !draft.work_ability ||
    !draft.energy_level ||
    !draft.mental_clarity ||
    !draft.symptom_burden ||
    !draft.effort_strain ||
    !draft.status
  ) {
    throw new Error("Rapporten mangler påkrevde felt.");
  }

  const report: Report = {
    ...baseFields(),
    type: "work_report",
    workplace: draft.workplace?.trim() || undefined,
    work_start_time: draft.work_start_time || undefined,
    work_end_time: draft.work_end_time || undefined,
    work_ability: draft.work_ability,
    energy_level: draft.energy_level,
    mental_clarity: draft.mental_clarity,
    symptom_burden: draft.symptom_burden,
    effort_strain: draft.effort_strain,
    status: draft.status,
    physical_energy: draft.physical_energy_detail ?? draft.energy_level,
    mental_energy: draft.mental_energy_detail ?? draft.energy_level,
    perceived_productivity: draft.perceived_productivity,
    task_completion: draft.task_completion,
    task_types: draft.task_types,
    main_limitations: draft.main_limitations,
    helpful_accommodations: draft.helpful_accommodations,
    note: draft.note.trim() || undefined
  };
  report.total_score_percent = calculateReportScore(report) ?? undefined;

  const signedReport = attachIntegrity(report);
  writeEntries([signedReport, ...readEntries()]);
  return signedReport;
}

export function createFollowup(draft: FollowupDraft): DelayedFollowup {
  if (!draft.worse_than_before) {
    throw new Error("Oppfølgingen mangler svar på om du er verre enn før økten.");
  }

  const followup: DelayedFollowup = {
    ...baseFields(),
    type: "delayed_followup",
    parent_report_id: draft.parent_report_id || draft.related_report_id || undefined,
    related_report_id: draft.related_report_id || draft.parent_report_id || undefined,
    worse_than_before: draft.worse_than_before,
    delayed_symptoms: draft.delayed_symptoms,
    recovery_status: draft.recovery_status,
    note: draft.note.trim() || undefined
  };

  const signedFollowup = attachIntegrity(followup);
  writeEntries([signedFollowup, ...readEntries()]);
  return signedFollowup;
}

export function listReports(): StoredEntry[] {
  return readEntries().sort((a, b) => getEntryTime(b) - getEntryTime(a));
}

export function getLastWorkReport(): Report | undefined {
  return listReports().find((entry): entry is Report => entry.type === "work_report");
}

export function getReport(id: string): StoredEntry | undefined {
  return readEntries().find((entry) => entry.id === id);
}

export function deleteReport(id: string) {
  writeEntries(readEntries().filter((entry) => entry.id !== id));
}

export function deleteAllReports() {
  writeEntries([]);
}

export function exportReports() {
  const reports = listReports();
  const payload: ExportPayload = {
    schema_version: 3,
    export_version: 3,
    exported_at: new Date().toISOString(),
    export_integrity: createExportIntegrity(reports),
    reports
  };
  return JSON.stringify(payload, null, 2);
}

export function previewImportReports(jsonText: string) {
  const imported = parseImportEntries(jsonText).map(normalizeStoredEntry).map(verifyEntryIntegrity);
  return { ...summarizeImport(imported, readEntries()), verification: summarizeVerification(imported) };
}

export function importReportsFromJson(jsonText: string): ImportSummary {
  const imported = parseImportEntries(jsonText).map(normalizeStoredEntry).map(verifyEntryIntegrity);
  const existing = readEntries();
  const summary = { ...summarizeImport(imported, existing), verification: summarizeVerification(imported) };
  const existingSignatures = new Set(existing.map(entrySignature));
  const existingById = new Map(existing.map((entry) => [entry.id, entry]));
  const additions: StoredEntry[] = [];

  for (const entry of imported) {
    const existingWithId = existingById.get(entry.id);
    if (existingWithId && entryContentSignature(existingWithId) !== entryContentSignature(entry)) continue;
    if (existingSignatures.has(entrySignature(entry))) continue;
    existingSignatures.add(entrySignature(entry));
    additions.push(entry);
  }

  writeEntries([...additions, ...existing].sort((a, b) => getEntryTime(b) - getEntryTime(a)));
  return summary;
}

function parseImportEntries(jsonText: string): StoredEntry[] {
  const parsed = JSON.parse(jsonText);
  const entries = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.reports) ? parsed.reports : null;
  if (!entries) throw new Error("Filen inneholder ikke en gjenkjennbar rapporteksport.");
  return entries;
}

function summarizeImport(imported: StoredEntry[], existing: StoredEntry[]): ImportSummary {
  const existingSignatures = new Set(existing.map(entrySignature));
  const existingById = new Map(existing.map((entry) => [entry.id, entry]));
  const seenImported = new Set<string>();
  const summary: ImportSummary = {
    reports_added: 0,
    followups_added: 0,
    duplicates_skipped: 0,
    conflicts_detected: 0
  };

  for (const entry of imported) {
    const signature = entrySignature(entry);
    const existingWithId = existingById.get(entry.id);
    if (existingWithId && entryContentSignature(existingWithId) !== entryContentSignature(entry)) {
      summary.conflicts_detected += 1;
      continue;
    }
    if (existingSignatures.has(signature) || seenImported.has(signature)) {
      summary.duplicates_skipped += 1;
      continue;
    }
    seenImported.add(signature);
    if (entry.type === "work_report") summary.reports_added += 1;
    if (entry.type === "delayed_followup") summary.followups_added += 1;
  }

  return summary;
}

function entrySignature(entry: Partial<StoredEntry>) {
  if (entry.id) return `id:${entry.id}`;
  return entryContentSignature(entry);
}

function entryContentSignature(entry: Partial<StoredEntry>) {
  if (entry.type === "work_report") {
    const report = entry as Partial<Report>;
    return [
      "report",
      report.created_at,
      report.report_date,
      report.report_time,
      report.work_ability,
      report.energy_level,
      report.status
    ].join("|");
  }
  const followup = entry as Partial<DelayedFollowup>;
  return ["followup", followup.created_at, followup.report_date, followup.report_time, followup.worse_than_before].join("|");
}

function normalizeStoredEntry(entry: StoredEntry): StoredEntry {
  if (entry.type === "work_report") {
    const { physical_energy_detail, mental_energy_detail, ...rest } = entry;
    const report: Report = {
      ...rest,
      task_types: rest.task_types ?? [],
      main_limitations: rest.main_limitations ?? [],
      helpful_accommodations: rest.helpful_accommodations ?? [],
      physical_energy: rest.physical_energy ?? physical_energy_detail ?? rest.energy_level,
      mental_energy: rest.mental_energy ?? mental_energy_detail ?? rest.energy_level
    };
    return {
      ...report,
      total_score_percent: report.total_score_percent ?? calculateReportScore(report) ?? undefined
    };
  }

  return {
    ...entry,
    parent_report_id: entry.parent_report_id ?? entry.related_report_id,
    related_report_id: entry.related_report_id ?? entry.parent_report_id,
    delayed_symptoms: entry.delayed_symptoms ?? []
  };
}
