import { beforeEach, describe, expect, it, vi } from "vitest";
import {
  createFollowup,
  exportReports,
  filterEntriesForExport,
  importReportsFromJson,
  listReports,
  previewImportReports,
  setDemoModeEnabled,
  updateFollowup,
  updateReport
} from "./storage";
import type { DelayedFollowup, ExportPayload, Report, StoredEntry } from "./types";

const store = new Map<string, string>();

beforeEach(() => {
  store.clear();
  vi.stubGlobal("localStorage", {
    getItem: (key: string) => store.get(key) ?? null,
    setItem: (key: string, value: string) => store.set(key, value),
    removeItem: (key: string) => store.delete(key),
    clear: () => store.clear()
  });
});

const report: Report = {
  id: "rapport-1",
  report_time: "08:00:00",
  report_date: "2026-05-27",
  created_at: "2026-05-27T06:00:00.000Z",
  type: "work_report",
  work_ability: 4,
  energy_level: 3,
  mental_clarity: 4,
  symptom_burden: 2,
  effort_strain: 3,
  status: "kan_fortsette",
  physical_energy: 3,
  mental_energy: 3,
  task_types: [],
  main_limitations: [],
  helpful_accommodations: []
};

function payload(reports: StoredEntry[]): ExportPayload {
  return {
    schema_version: 2,
    export_version: 2,
    exported_at: "2026-05-27T10:00:00.000Z",
    reports
  };
}

describe("ordinær brukerimport", () => {
  it("forhåndsviser import uten å lagre data", () => {
    const summary = previewImportReports(JSON.stringify(payload([report])));

    expect(summary.reports_added).toBe(1);
    expect(listReports()).toHaveLength(0);
  });

  it("importerer nye rapporter og hopper over duplikater", () => {
    const first = importReportsFromJson(JSON.stringify(payload([report])));
    const second = importReportsFromJson(JSON.stringify(payload([report])));

    expect(first.reports_added).toBe(1);
    expect(second.reports_added).toBe(0);
    expect(second.duplicates_skipped).toBe(1);
    expect(listReports()).toHaveLength(1);
  });

  it("oppdager konflikt når samme ID har annet innhold", () => {
    importReportsFromJson(JSON.stringify(payload([report])));
    const changed = { ...report, energy_level: 1 as const };
    const summary = previewImportReports(JSON.stringify(payload([changed])));

    expect(summary.conflicts_detected).toBe(1);
    expect(summary.reports_added).toBe(0);
  });

  it("holder demodata adskilt fra normale rapporter og blokkerer normal import", () => {
    setDemoModeEnabled(true);

    expect(listReports(true).length).toBeGreaterThan(0);
    expect(listReports()).toHaveLength(0);

    const demoExport = exportReports(true);
    expect(JSON.parse(demoExport).data_mode).toBe("demo");
    expect(() => previewImportReports(demoExport)).toThrow("demodata");
  });

  it("tillater import av demodata i demo-modus", () => {
    const demoReport = { ...report, id: "demo-arbeidspuls-test", demo: true };
    const summary = importReportsFromJson(JSON.stringify({ ...payload([demoReport]), data_mode: "demo", contains_demo_data: true }), true);

    expect(summary.demo_entries_detected).toBe(1);
    expect(listReports(true).some((entry) => entry.id === "demo-arbeidspuls-test" && entry.demo)).toBe(true);
    expect(listReports()).toHaveLength(0);
  });

  it("tillater redigering innen 24 timer og beholder ID", () => {
    const fresh = { ...report, created_at: new Date().toISOString() };
    importReportsFromJson(JSON.stringify(payload([fresh])));

    const updated = updateReport(fresh.id, {
      workplace: "Nytt sted",
      work_ability: 5,
      energy_level: 3,
      mental_clarity: 4,
      symptom_burden: 2,
      effort_strain: 3,
      status: "kan_fortsette",
      task_types: [],
      main_limitations: [],
      helpful_accommodations: [],
      note: "Oppdatert"
    });

    expect(updated.id).toBe(fresh.id);
    expect(updated.created_at).toBe(fresh.created_at);
    expect(updated.updated_at).toBeTruthy();
    expect(updated.integrity?.verification_status).toBe("valid");
    const stored = listReports()[0];
    expect(stored.type).toBe("work_report");
    expect(stored.type === "work_report" ? stored.work_ability : null).toBe(5);
  });

  it("blokkerer redigering etter 24 timer", () => {
    const old = { ...report, created_at: "2020-01-01T00:00:00.000Z" };
    importReportsFromJson(JSON.stringify(payload([old])));

    expect(() =>
      updateReport(old.id, {
        work_ability: 5,
        energy_level: 3,
        mental_clarity: 4,
        symptom_burden: 2,
        effort_strain: 3,
        status: "kan_fortsette",
        task_types: [],
        main_limitations: [],
        helpful_accommodations: [],
        note: ""
      })
    ).toThrow("24 timer");
  });

  it("tillater bare nyeste rapport som parent for ny oppfølging", () => {
    const older = { ...report, id: "rapport-eldre", created_at: "2026-05-26T06:00:00.000Z", report_date: "2026-05-26" };
    const newer = { ...report, id: "rapport-nyere", created_at: "2026-05-28T06:00:00.000Z", report_date: "2026-05-28" };
    importReportsFromJson(JSON.stringify(payload([older, newer])));

    expect(() =>
      createFollowup({
        parent_report_id: older.id,
        related_report_id: older.id,
        worse_than_before: "litt",
        delayed_symptoms: [],
        note: ""
      })
    ).toThrow("nyeste rapport");

    const saved = createFollowup({
      parent_report_id: newer.id,
      related_report_id: newer.id,
      worse_than_before: "litt",
      delayed_symptoms: [],
      note: ""
    });
    expect(saved.parent_report_id).toBe(newer.id);
  });

  it("redigerer oppfølging innen 24 timer uten å endre ID", () => {
    const freshReport = { ...report, id: "rapport-fersk", created_at: new Date().toISOString(), report_date: "2026-05-29" };
    const followup: DelayedFollowup = {
      id: "oppfolging-fersk",
      created_at: new Date().toISOString(),
      report_date: "2026-05-29",
      report_time: "10:00:00",
      type: "delayed_followup",
      parent_report_id: freshReport.id,
      worse_than_before: "litt",
      delayed_symptoms: [],
      note: "før"
    };
    importReportsFromJson(JSON.stringify({ ...payload([freshReport]), reports: [freshReport, followup] }));

    const updated = updateFollowup(followup.id, {
      parent_report_id: freshReport.id,
      related_report_id: freshReport.id,
      worse_than_before: "mye",
      delayed_symptoms: ["fatigue"],
      note: "etter"
    });

    expect(updated.id).toBe(followup.id);
    expect(updated.created_at).toBe(followup.created_at);
    expect(updated.worse_than_before).toBe("mye");
    expect(updated.integrity?.verification_status).toBe("valid");
  });

  it("filtrerer eksport på fra-dato, til-dato og intervall inklusivt", () => {
    const first = { ...report, id: "rapport-1", created_at: "2026-05-27T06:00:00.000Z", report_date: "2026-05-27" };
    const second = { ...report, id: "rapport-2", created_at: "2026-05-28T06:00:00.000Z", report_date: "2026-05-28" };
    const followup: DelayedFollowup = {
      id: "oppfolging-1",
      created_at: "2026-05-29T08:00:00.000Z",
      report_date: "2026-05-29",
      report_time: "10:00:00",
      type: "delayed_followup",
      parent_report_id: second.id,
      worse_than_before: "litt",
      delayed_symptoms: []
    };
    const entries = [first, second, followup];

    expect(filterEntriesForExport(entries, {})).toHaveLength(3);
    expect(filterEntriesForExport(entries, { fromDate: "2026-05-28" }).map((entry) => entry.id)).toEqual(["oppfolging-1", "rapport-2"]);
    expect(filterEntriesForExport(entries, { toDate: "2026-05-28" }).map((entry) => entry.id)).toEqual(["rapport-2", "rapport-1"]);
    expect(filterEntriesForExport(entries, { fromDate: "2026-05-28", toDate: "2026-05-28" }).map((entry) => entry.id)).toEqual(["rapport-2"]);
  });

  it("eksporterer filtrert JSON med oppdatert manifest og blokkerer ugyldig intervall", () => {
    const first = { ...report, id: "rapport-1", created_at: "2026-05-27T06:00:00.000Z", report_date: "2026-05-27" };
    const second = { ...report, id: "rapport-2", created_at: "2026-05-28T06:00:00.000Z", report_date: "2026-05-28" };
    importReportsFromJson(JSON.stringify(payload([first, second])));

    const exported = JSON.parse(exportReports(false, { fromDate: "2026-05-28", toDate: "2026-05-28" })) as ExportPayload;

    expect(exported.reports.map((entry) => entry.id)).toEqual(["rapport-2"]);
    expect(exported.export_integrity?.manifest_hash_sha256).toBeTruthy();
    expect(() => exportReports(false, { fromDate: "2026-05-29", toDate: "2026-05-28" })).toThrow("Fra-dato");
  });
});
