import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
  type ReactNode,
} from "react";

import { loadDatabase, saveTables } from "./sheets.functions";
import type { SheetName, SheetRow } from "./sheets-schema";

export type DbStatus = "memuat" | "siap" | "menyimpan" | "gagal";


export type Role =
  | "Admin"
  | "Petugas Piket"
  | "Wali Kelas"
  | "Guru BK"
  | "Satpam"
  | "Kepala Sekolah"
  | "Waka Kesiswaan"
  | "Guru Mapel"
  | "Operator Dapodik"
  | "Orang Tua";

export const ROLES: Role[] = [
  "Admin",
  "Petugas Piket",
  "Wali Kelas",
  "Guru BK",
  "Satpam",
  "Kepala Sekolah",
  "Waka Kesiswaan",
  "Guru Mapel",
  "Operator Dapodik",
  "Orang Tua",
];

export const STATUS_DAPODIK = [
  "Belum Diverifikasi",
  "Terverifikasi",
  "Perbaikan Diajukan",
] as const;
export type StatusDapodik = (typeof STATUS_DAPODIK)[number];

/** Data siswa versi Dapodik yang diinput operator dan divalidasi orang tua. */
export type Dapodik = {
  id: string;
  nama: string;
  kelas: string;
  tempatLahir: string;
  tanggalLahir: string;
  nipd: string;
  nisn: string;
  nik: string;
  jk: "L" | "P";
  agama: string;
  namaAyah: string;
  namaIbu: string;
  hpOrtu: string;
  hpSiswa: string;
  alamat: string;
  status: StatusDapodik;
  catatanOrtu?: string;
  diperbaruiOleh?: string;
  diperbaruiPada?: string;
};

export const AGAMA_LIST = ["Islam", "Kristen", "Katolik", "Hindu", "Buddha", "Konghucu"];

export type User = {
  id: string;
  username: string;
  password: string;
  role: Role;
  nama: string;
  keterangan: string;
  anak?: string;
  /** Kelas yang diampu sebagai wali kelas (dipakai guru mapel yang merangkap walas). */
  kelasWali?: string;
  nonaktif?: boolean;
};

/** Kelas perwalian seorang pengguna: Wali Kelas murni atau guru mapel merangkap walas. */
export function waliKelasOf(u?: User | null): string {
  if (!u) return "";
  if (u.role === "Wali Kelas") return u.keterangan && u.keterangan !== "-" ? u.keterangan : "";
  return u.kelasWali && u.kelasWali !== "-" ? u.kelasWali : "";
}

export type Siswa = { id: string; nis: string; nama: string; kelas: string; jk: "L" | "P" };

export type Jadwal = {
  id: string;
  hari: string;
  nama_grup: string;
  daftar_guru: string;
  jam_piket: string;
  keterangan: string;
};

export type Tamu = {
  id: string;
  tanggal: string;
  waktu: string;
  nama: string;
  instansi: string;
  tujuan: string;
  dituju: string;
  keterangan: string;
  foto?: string;
  driveUrl?: string;
};

export type Pelanggaran = {
  id: string;
  tanggal: string;
  waktu: string;
  nama: string;
  kelas: string;
  jenis: string;
  tindakan: string;
  /** Nama & peran petugas yang menginput laporan, mis. "Budi Santoso, S.Pd · Petugas Piket" */
  pelapor?: string;
};

export const JENIS_PRESTASI = ["Akademik", "Non-Akademik"] as const;
export type JenisPrestasi = (typeof JENIS_PRESTASI)[number];

export const TINGKAT_PRESTASI = [
  "Tingkat Sekolah",
  "Tingkat Kota",
  "Tingkat Provinsi",
  "Tingkat Nasional",
] as const;
export type TingkatPrestasi = (typeof TINGKAT_PRESTASI)[number];

export type Prestasi = {
  id: string;
  tanggal: string;
  nama: string;
  kelas: string;
  jenis: JenisPrestasi;
  tingkat: TingkatPrestasi;
  kegiatan: string;
  peringkat: string;
  penyelenggara: string;
  keterangan: string;
  /** Link Google Drive sertifikat/piagam/surat keterangan */
  sertifikatUrl?: string;
  /** Link Google Drive foto siswa saat menerima penghargaan */
  fotoUrl?: string;
  pencatat: string;
};

export type StatusIzin = "Menunggu" | "Diizinkan Keluar" | "Sudah Kembali";

export type Izin = {
  id: string;
  tanggal: string;
  waktu_keluar: string;
  waktu_kembali: string;
  nama: string;
  kelas: string;
  alasan: string;
  status: StatusIzin;
};

export type StatusIzinGuru = "Menunggu" | "Disetujui" | "Ditolak";

export type IzinGuru = {
  id: string;
  tanggal: string;
  guru: string;
  mapel: string;
  jenis: "Izin" | "Sakit";
  alasan: string;
  status: StatusIzinGuru;
  catatan: string;
  lampiran?: string;
  driveUrl?: string;
};

export const JENIS_IZIN_GURU: IzinGuru["jenis"][] = ["Izin", "Sakit"];

export type JenisPemberitahuan = "Pemberitahuan" | "Surat Pemanggilan";
export const JENIS_PEMBERITAHUAN: JenisPemberitahuan[] = ["Pemberitahuan", "Surat Pemanggilan"];

export type PemberitahuanBk = {
  id: string;
  tanggal: string;
  waktu: string;
  jenis: JenisPemberitahuan;
  nama: string;
  kelas: string;
  judul: string;
  isi: string;
  lampiran?: string;
  pengirim: string;
};

export type JenisSaran = "Saran" | "Laporan" | "Pengaduan";
export const JENIS_SARAN: JenisSaran[] = ["Saran", "Laporan", "Pengaduan"];

export type SaranOrtu = {
  id: string;
  tanggal: string;
  waktu: string;
  jenis: JenisSaran;
  pengirim: string;
  anak: string;
  kelas: string;
  judul: string;
  isi: string;
  lampiran?: string;
  status: "Terkirim" | "Ditanggapi";
  tanggapan: string;
};

export type TataTertib = { id: string; kategori: string; isi: string; sanksi: string };
export type Tautan = {
  id: string;
  jenis: "Tata Tertib" | "Jadwal Pelajaran";
  judul: string;
  kelas: string;
  url: string;
  gambar: string;
};
export const JENIS_TAUTAN: Tautan["jenis"][] = ["Tata Tertib", "Jadwal Pelajaran"];
export const JENJANG_LIST = ["VII", "VIII", "IX"] as const;
export type Jenjang = "Semua" | (typeof JENJANG_LIST)[number];
export const JENJANG_OPTIONS: Jenjang[] = ["Semua", ...JENJANG_LIST];
export const jenjangOfKelas = (kelas: string) =>
  (kelas || "").split(/[-\s]/)[0]?.toUpperCase() ?? "";

export type Pengumuman = {
  id: string;
  tanggal: string;
  judul: string;
  isi: string;
  lampiran?: string;
  jenjang?: Jenjang;
  dihapusPada?: string;
};
export type JadwalMengajar = {
  id: string;
  guru: string;
  hari: string;
  jam_ke: string;
  pukul: string;
  mapel: string;
  kelas: string;
};

export const HARI_LIST = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"] as const;
export const JAM_KE_LIST = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];

export type JadwalPelajaran = {
  id: string;
  kelas: string;
  hari: string;
  jam: string;
  mapel: string;
  guru: string;
};

const initialUsers: User[] = [
  {
    id: "U1",
    username: "admin",
    password: "edudigital",
    role: "Admin",
    nama: "Administrator Sistem",
    keterangan: "-",
  },
  {
    id: "U2",
    username: "piket",
    password: "edudigital",
    role: "Petugas Piket",
    nama: "Budi Santoso, S.Pd",
    keterangan: "-",
  },
  {
    id: "U3",
    username: "wali",
    password: "edudigital",
    role: "Wali Kelas",
    nama: "Siti Aminah, S.Pd",
    keterangan: "VII-A",
  },
  {
    id: "U4",
    username: "wali2",
    password: "edudigital",
    role: "Wali Kelas",
    nama: "Rina Wijaya, S.Pd",
    keterangan: "VII-B",
  },
  {
    id: "U5",
    username: "bk",
    password: "edudigital",
    role: "Guru BK",
    nama: "Drs. Mulyono",
    keterangan: "-",
  },
  {
    id: "U6",
    username: "satpam",
    password: "edudigital",
    role: "Satpam",
    nama: "Hasan",
    keterangan: "-",
  },
  {
    id: "U7",
    username: "kepsek",
    password: "edudigital",
    role: "Kepala Sekolah",
    nama: "Hj. Ratna, M.Pd",
    keterangan: "-",
  },
  {
    id: "U9",
    username: "guru",
    password: "edudigital",
    role: "Guru Mapel",
    nama: "Dewi Lestari, S.Pd",
    keterangan: "Matematika",
  },
  {
    id: "U8",
    username: "ortu",
    password: "edudigital",
    role: "Orang Tua",
    nama: "Bapak Yanto",
    keterangan: "VII-A",
    anak: "Andi Saputra",
  },
];

const initialKelas = [
  "VII-A",
  "VII-B",
  "VII-C",
  "VIII-A",
  "VIII-B",
  "VIII-C",
  "IX-A",
  "IX-B",
  "IX-C",
];

const initialJadwal: Jadwal[] = [
  {
    id: "J1",
    hari: "Senin",
    nama_grup: "Tim Piket A",
    daftar_guru: "Budi Santoso, S.Pd & Siti Aminah, S.Pd",
    jam_piket: "06:30 - 14:00",
    keterangan: "Piket Gerbang Utama",
  },
  {
    id: "J2",
    hari: "Selasa",
    nama_grup: "Tim Piket B",
    daftar_guru: "Drs. Mulyono & Hj. Ratna, M.Pd",
    jam_piket: "06:30 - 14:00",
    keterangan: "Piket Kedisiplinan",
  },
];

const initialTamu: Tamu[] = [
  {
    id: "T1",
    tanggal: "2026-07-21",
    waktu: "08:00 WIB",
    nama: "Bapak Yanto",
    instansi: "Wali Murid",
    tujuan: "Konsultasi Raport",
    dituju: "Wali Kelas VII-A",
    keterangan: "-",
  },
];

const initialPrestasi: Prestasi[] = [
  {
    id: "PR1",
    tanggal: "2026-07-18",
    nama: "Andi Saputra",
    kelas: "VII-A",
    jenis: "Akademik",
    tingkat: "Tingkat Kota",
    kegiatan: "Olimpiade Matematika",
    peringkat: "Juara 2",
    penyelenggara: "Dinas Pendidikan Kota Palangka Raya",
    keterangan: "-",
    pencatat: "Waka Kesiswaan",
  },
];

const initialPelanggaran: Pelanggaran[] = [
  {
    id: "P1",
    tanggal: "2026-07-20",
    waktu: "09:00 WIB",
    nama: "Andi Saputra",
    kelas: "VII-A",
    jenis: "Rambut Gondrong",
    tindakan: "Teguran Lisan & Pembinaan",
    pelapor: "Budi Santoso, S.Pd · Petugas Piket",
  },
];

const initialIzin: Izin[] = [
  {
    id: "I1",
    tanggal: "2026-07-21",
    waktu_keluar: "10:00 WIB",
    waktu_kembali: "-",
    nama: "Andi Saputra",
    kelas: "VII-A",
    alasan: "Pulang Sakit Demam",
    status: "Menunggu",
  },
];

const initialIzinGuru: IzinGuru[] = [
  {
    id: "IG1",
    tanggal: "2026-07-21",
    guru: "Dewi Lestari, S.Pd",
    mapel: "Matematika",
    jenis: "Sakit",
    alasan: "Demam dan perlu istirahat sesuai anjuran dokter.",
    status: "Menunggu",
    catatan: "-",
  },
];

const initialSiswa: Siswa[] = [
  { id: "S1", nis: "10101", nama: "Andi Saputra", kelas: "VII-A", jk: "L" },
  { id: "S2", nis: "10102", nama: "Budi Santoso", kelas: "VII-A", jk: "L" },
  { id: "S3", nis: "10103", nama: "Citra Kirana", kelas: "VII-B", jk: "P" },
];

const initialTataTertib: TataTertib[] = [
  {
    id: "TT1",
    kategori: "Kedisiplinan",
    isi: "Siswa hadir di sekolah paling lambat pukul 06.45 WIB.",
    sanksi: "Teguran & pembinaan",
  },
  {
    id: "TT2",
    kategori: "Penampilan",
    isi: "Rambut siswa putra rapi dan tidak melebihi kerah baju.",
    sanksi: "Pemotongan rambut di sekolah",
  },
  {
    id: "TT3",
    kategori: "Perizinan",
    isi: "Meninggalkan sekolah wajib membawa surat izin dari petugas piket.",
    sanksi: "Poin pelanggaran",
  },
];

const initialPemberitahuanBk: PemberitahuanBk[] = [
  {
    id: "PB1",
    tanggal: "2026-07-21",
    waktu: "10:15 WIB",
    jenis: "Pemberitahuan",
    nama: "Andi Saputra",
    kelas: "VII-A",
    judul: "Pembinaan Kedisiplinan",
    isi: "Ananda telah mendapat pembinaan terkait kerapian. Mohon dukungan orang tua di rumah.",
    lampiran: "",
    pengirim: "Drs. Mulyono",
  },
];

const initialPengumuman: Pengumuman[] = [
  {
    id: "PG1",
    tanggal: "2026-07-20",
    judul: "Rapat Orang Tua Siswa",
    isi: "Rapat komite bersama orang tua siswa dilaksanakan Sabtu, 25 Juli 2026 pukul 08.00 WIB di aula sekolah.",
  },
];

const initialJadwalPelajaran: JadwalPelajaran[] = [
  {
    id: "JP1",
    kelas: "VII-A",
    hari: "Senin",
    jam: "07.00 - 08.30",
    mapel: "Matematika",
    guru: "Siti Aminah, S.Pd",
  },
  {
    id: "JP2",
    kelas: "VII-A",
    hari: "Senin",
    jam: "08.30 - 10.00",
    mapel: "Bahasa Indonesia",
    guru: "Budi Santoso, S.Pd",
  },
  {
    id: "JP3",
    kelas: "VII-B",
    hari: "Selasa",
    jam: "07.00 - 08.30",
    mapel: "IPA",
    guru: "Rina Wijaya, S.Pd",
  },
];

const initialJadwalMengajar: JadwalMengajar[] = [
  {
    id: "JM1",
    guru: "Dewi Lestari, S.Pd",
    hari: "Senin",
    jam_ke: "1",
    pukul: "07.00 - 08.30",
    mapel: "Matematika",
    kelas: "VII-A",
  },
  {
    id: "JM2",
    guru: "Dewi Lestari, S.Pd",
    hari: "Selasa",
    jam_ke: "3",
    pukul: "09.00 - 10.30",
    mapel: "Matematika",
    kelas: "VII-B",
  },
];

const initialTautan: Tautan[] = [
  {
    id: "TA1",
    jenis: "Tata Tertib",
    judul: "Tata Tertib Siswa SMPN 8",
    kelas: "",
    url: "https://example.com/tata-tertib.pdf",
    gambar: "",
  },
  {
    id: "TA2",
    jenis: "Jadwal Pelajaran",
    judul: "Jadwal Pelajaran Kelas VII-A",
    kelas: "VII-A",
    url: "https://example.com/jadwal-vii-a.pdf",
    gambar: "",
  },
];

export const newId = (prefix: string) =>
  `${prefix}${Math.random().toString(36).slice(2, 8).toUpperCase()}`;

export const todayISO = () => new Date().toISOString().slice(0, 10);
export const nowTime = () =>
  `${new Date().toLocaleTimeString("id-ID", { hour: "2-digit", minute: "2-digit" })} WIB`;

type Store = {
  currentUser: User | null;
  login: (username: string, password: string) => User | null;
  logout: () => void;
  users: User[];
  setUsers: React.Dispatch<React.SetStateAction<User[]>>;
  masterKelas: string[];
  setMasterKelas: React.Dispatch<React.SetStateAction<string[]>>;
  kelasList: string[];
  siswa: Siswa[];
  setSiswa: React.Dispatch<React.SetStateAction<Siswa[]>>;
  jadwal: Jadwal[];
  setJadwal: React.Dispatch<React.SetStateAction<Jadwal[]>>;
  tamu: Tamu[];
  setTamu: React.Dispatch<React.SetStateAction<Tamu[]>>;
  pelanggaran: Pelanggaran[];
  setPelanggaran: React.Dispatch<React.SetStateAction<Pelanggaran[]>>;
  izin: Izin[];
  saranOrtu: SaranOrtu[];
  setSaranOrtu: React.Dispatch<React.SetStateAction<SaranOrtu[]>>;
  pemberitahuanBk: PemberitahuanBk[];
  setPemberitahuanBk: React.Dispatch<React.SetStateAction<PemberitahuanBk[]>>;
  izinGuru: IzinGuru[];
  setIzinGuru: React.Dispatch<React.SetStateAction<IzinGuru[]>>;
  setIzin: React.Dispatch<React.SetStateAction<Izin[]>>;
  tataTertib: TataTertib[];
  setTataTertib: React.Dispatch<React.SetStateAction<TataTertib[]>>;
  pengumumanHistori: Pengumuman[];
  setPengumumanHistori: React.Dispatch<React.SetStateAction<Pengumuman[]>>;
  pengumuman: Pengumuman[];
  setPengumuman: React.Dispatch<React.SetStateAction<Pengumuman[]>>;
  jadwalMengajar: JadwalMengajar[];
  setJadwalMengajar: React.Dispatch<React.SetStateAction<JadwalMengajar[]>>;
  jadwalPelajaran: JadwalPelajaran[];
  setJadwalPelajaran: React.Dispatch<React.SetStateAction<JadwalPelajaran[]>>;
  dapodik: Dapodik[];
  setDapodik: React.Dispatch<React.SetStateAction<Dapodik[]>>;
  tautan: Tautan[];
  setTautan: React.Dispatch<React.SetStateAction<Tautan[]>>;
  driveTamuUrl: string;
  setDriveTamuUrl: React.Dispatch<React.SetStateAction<string>>;
  driveIzinGuruUrl: string;
  setDriveIzinGuruUrl: React.Dispatch<React.SetStateAction<string>>;
  driveSuratBkUrl: string;
  setDriveSuratBkUrl: React.Dispatch<React.SetStateAction<string>>;
  prestasi: Prestasi[];
  setPrestasi: React.Dispatch<React.SetStateAction<Prestasi[]>>;
  drivePrestasiUrl: string;
  setDrivePrestasiUrl: React.Dispatch<React.SetStateAction<string>>;
  driveSaranUrl: string;
  setDriveSaranUrl: React.Dispatch<React.SetStateAction<string>>;
  dismissedNotif: string[];
  dismissNotif: (id: string) => void;
  dbStatus: DbStatus;
  spreadsheetId: string;
  setSpreadsheetId: (id: string) => void;
  reloadDatabase: () => void;
  backupDatabase: () => Record<string, SheetRow[]>;
  restoreDatabase: (db: Record<string, SheetRow[]>) => Promise<void>;



};

const SipContext = createContext<Store | null>(null);

export function SipProvider({ children }: { children: ReactNode }) {
  const [currentUser, setCurrentUser] = useState<User | null>(null);
  const [users, setUsers] = useState<User[]>(initialUsers);
  const [masterKelas, setMasterKelas] = useState<string[]>(initialKelas);
  const [siswa, setSiswa] = useState<Siswa[]>(initialSiswa);
  const [jadwal, setJadwal] = useState<Jadwal[]>(initialJadwal);
  const [tamu, setTamu] = useState<Tamu[]>(initialTamu);
  const [pelanggaran, setPelanggaran] = useState<Pelanggaran[]>(initialPelanggaran);
  const [izin, setIzin] = useState<Izin[]>(initialIzin);
  const [izinGuru, setIzinGuru] = useState<IzinGuru[]>(initialIzinGuru);
  const [tataTertib, setTataTertib] = useState<TataTertib[]>(initialTataTertib);
  const [pengumuman, setPengumuman] = useState<Pengumuman[]>(initialPengumuman);
  const [pengumumanHistori, setPengumumanHistori] = useState<Pengumuman[]>([]);
  const [pemberitahuanBk, setPemberitahuanBk] = useState<PemberitahuanBk[]>(initialPemberitahuanBk);
  const [saranOrtu, setSaranOrtu] = useState<SaranOrtu[]>([]);
  const [jadwalPelajaran, setJadwalPelajaran] = useState<JadwalPelajaran[]>(initialJadwalPelajaran);
  const [jadwalMengajar, setJadwalMengajar] = useState<JadwalMengajar[]>(initialJadwalMengajar);
  const [tautan, setTautan] = useState<Tautan[]>(initialTautan);
  const [dapodik, setDapodik] = useState<Dapodik[]>([]);
  const [driveTamuUrl, setDriveTamuUrl] = useState<string>("");
  const [driveIzinGuruUrl, setDriveIzinGuruUrl] = useState<string>("");
  const [driveSuratBkUrl, setDriveSuratBkUrl] = useState<string>("");
  const [driveSaranUrl, setDriveSaranUrl] = useState<string>("");
  const [prestasi, setPrestasi] = useState<Prestasi[]>(initialPrestasi);
  const [drivePrestasiUrl, setDrivePrestasiUrl] = useState<string>("");
  const [dismissedNotif, setDismissedNotif] = useState<string[]>([]);
  const [hydrated, setHydrated] = useState(false);
  const [dbStatus, setDbStatus] = useState<DbStatus>("memuat");
  const [spreadsheetId, setSpreadsheetIdState] = useState<string>("");
  const [muatUlang, setMuatUlang] = useState(0);
  const lastSaved = useRef<Record<string, string>>({});


  // ID spreadsheet dapat diatur manual dari menu Database (disimpan di perangkat ini).
  useEffect(() => {
    setSpreadsheetIdState(localStorage.getItem("sip_spreadsheet_id") ?? "");
  }, []);

  const setSpreadsheetId = useCallback((id: string) => {
    const bersih = id.trim();
    if (bersih) localStorage.setItem("sip_spreadsheet_id", bersih);
    else localStorage.removeItem("sip_spreadsheet_id");
    lastSaved.current = {};
    setSpreadsheetIdState(bersih);
  }, []);

  const reloadDatabase = useCallback(() => {
    lastSaved.current = {};
    setDbStatus("memuat");
    setMuatUlang((n) => n + 1);
  }, []);

  /** Menerapkan isi database ke seluruh state aplikasi. */
  const applyDatabase = useCallback(
    (db: Record<string, Record<string, string>[]>, timpaKosong = false) => {
      const isi = <T,>(key: string, set: (v: T[]) => void) => {
        const rows = db[key];
        if (rows?.length || (timpaKosong && rows)) set((rows ?? []) as unknown as T[]);
      };
      isi<User>("users", setUsers);
      if (db["kelas"]?.length || (timpaKosong && db["kelas"]))
        setMasterKelas(((db["kelas"] ?? []) as { nama?: string }[]).map((r) => r.nama ?? "").filter(Boolean));
      isi<Siswa>("siswa", setSiswa);
      isi<Pelanggaran>("pelanggaran", setPelanggaran);
      isi<Izin>("izin", setIzin);
      isi<Jadwal>("jadwal_piket", setJadwal);
      isi<Tamu>("tamu", setTamu);
      isi<IzinGuru>("izin_guru", setIzinGuru);
      isi<Prestasi>("prestasi", setPrestasi);
      isi<TataTertib>("tata_tertib", setTataTertib);
      isi<Pengumuman>("pengumuman", setPengumuman);
      isi<Pengumuman>("pengumuman_histori", setPengumumanHistori);
      isi<PemberitahuanBk>("pemberitahuan_bk", setPemberitahuanBk);
      isi<SaranOrtu>("saran_ortu", setSaranOrtu);
      isi<JadwalPelajaran>("jadwal_pelajaran", setJadwalPelajaran);
      isi<JadwalMengajar>("jadwal_mengajar", setJadwalMengajar);
      isi<Tautan>("tautan", setTautan);
      isi<Dapodik>("dapodik", setDapodik);
      const pengaturan = new Map(
        (db["pengaturan"] ?? []).map((r) => [r["kunci"] ?? "", r["nilai"] ?? ""]),
      );
      if (pengaturan.size) {
        setDriveTamuUrl(pengaturan.get("driveTamuUrl") ?? "");
        setDriveIzinGuruUrl(pengaturan.get("driveIzinGuruUrl") ?? "");
        setDriveSuratBkUrl(pengaturan.get("driveSuratBkUrl") ?? "");
        setDriveSaranUrl(pengaturan.get("driveSaranUrl") ?? "");
        setDrivePrestasiUrl(pengaturan.get("drivePrestasiUrl") ?? "");
      }
    },
    [],
  );

  // Muat data dari Google Sheets (penyimpanan pusat) setelah hidrasi.
  useEffect(() => {
    let batal = false;
    (async () => {
      try {
        const db = (await loadDatabase({ data: { spreadsheetId } })) as Record<
          string,
          Record<string, string>[]
        >;
        if (batal) return;
        applyDatabase(db);
        setDbStatus("siap");
      } catch (err) {
        console.error(err);
        if (!batal) setDbStatus("gagal");
      } finally {
        if (!batal) setHydrated(true);
      }
    })();
    return () => {
      batal = true;
    };
  }, [spreadsheetId, muatUlang, applyDatabase]);

  // Kumpulan seluruh tabel dalam format baris spreadsheet (dipakai simpan & backup).
  const tabelSemua = useMemo<Record<SheetName, SheetRow[]>>(
    () => ({
      users: users as unknown as SheetRow[],
      kelas: masterKelas.map((nama) => ({ nama })),
      siswa: siswa as unknown as SheetRow[],
      pelanggaran: pelanggaran as unknown as SheetRow[],
      izin: izin as unknown as SheetRow[],
      jadwal_piket: jadwal as unknown as SheetRow[],
      tamu: tamu as unknown as SheetRow[],
      izin_guru: izinGuru as unknown as SheetRow[],
      prestasi: prestasi as unknown as SheetRow[],
      tata_tertib: tataTertib as unknown as SheetRow[],
      pengumuman: pengumuman as unknown as SheetRow[],
      pengumuman_histori: pengumumanHistori as unknown as SheetRow[],
      pemberitahuan_bk: pemberitahuanBk as unknown as SheetRow[],
      saran_ortu: saranOrtu as unknown as SheetRow[],
      jadwal_pelajaran: jadwalPelajaran as unknown as SheetRow[],
      jadwal_mengajar: jadwalMengajar as unknown as SheetRow[],
      tautan: tautan as unknown as SheetRow[],
      dapodik: dapodik as unknown as SheetRow[],
      pengaturan: [
        { kunci: "driveTamuUrl", nilai: driveTamuUrl },
        { kunci: "driveIzinGuruUrl", nilai: driveIzinGuruUrl },
        { kunci: "driveSuratBkUrl", nilai: driveSuratBkUrl },
        { kunci: "driveSaranUrl", nilai: driveSaranUrl },
        { kunci: "drivePrestasiUrl", nilai: drivePrestasiUrl },
      ],
    }),
    [
      users,
      masterKelas,
      siswa,
      pelanggaran,
      izin,
      jadwal,
      tamu,
      izinGuru,
      prestasi,
      tataTertib,
      pengumuman,
      pengumumanHistori,
      pemberitahuanBk,
      saranOrtu,
      jadwalPelajaran,
      jadwalMengajar,
      tautan,
      dapodik,
      driveTamuUrl,
      driveIzinGuruUrl,
      driveSuratBkUrl,
      driveSaranUrl,
      drivePrestasiUrl,
    ],
  );

  const backupDatabase = useCallback(
    () => JSON.parse(JSON.stringify(tabelSemua)) as Record<string, SheetRow[]>,
    [tabelSemua],
  );

  /** Memulihkan data dari file backup lalu menyimpannya ke spreadsheet aktif. */
  const restoreDatabase = useCallback(
    async (db: Record<string, SheetRow[]>) => {
      applyDatabase(db as unknown as Record<string, Record<string, string>[]>, true);
      setDbStatus("menyimpan");
      try {
        await saveTables({ data: { tables: db as Partial<Record<SheetName, SheetRow[]>>, spreadsheetId } });
        lastSaved.current = {};
        setDbStatus("siap");
      } catch (err) {
        console.error(err);
        setDbStatus("gagal");
        throw err;
      }
    },
    [applyDatabase, spreadsheetId],
  );

  // Simpan otomatis setiap perubahan ke spreadsheet (ditunda agar tidak boros kuota).
  useEffect(() => {
    if (!hydrated) return;
    const t = setTimeout(() => {
      const berubah: Partial<Record<SheetName, SheetRow[]>> = {};
      (Object.keys(tabelSemua) as SheetName[]).forEach((table) => {
        const snapshot = JSON.stringify(tabelSemua[table]);
        if (lastSaved.current[table] === snapshot) return;
        lastSaved.current[table] = snapshot;
        berubah[table] = tabelSemua[table];
      });
      if (!Object.keys(berubah).length) return;
      setDbStatus("menyimpan");
      void saveTables({ data: { tables: berubah, spreadsheetId } })
        .then(() => setDbStatus("siap"))
        .catch((err) => {
          console.error(err);
          (Object.keys(berubah) as SheetName[]).forEach((t2) => delete lastSaved.current[t2]);
          setDbStatus("gagal");
        });
    }, 1500);
    return () => clearTimeout(t);
  }, [hydrated, tabelSemua, spreadsheetId]);





  const login = useCallback(
    (username: string, password: string) => {
      const found =
        users.find(
          (u) =>
            u.username.trim().toLowerCase() === username.trim().toLowerCase() &&
            u.password.trim() === password.trim(),
        ) ?? null;
      if (found?.nonaktif) return null;
      if (found) {
        setCurrentUser(found);
        setDismissedNotif([]);
      }
      return found;
    },
    [users],
  );

  const logout = useCallback(() => setCurrentUser(null), []);
  const dismissNotif = useCallback(
    (id: string) => setDismissedNotif((prev) => (prev.includes(id) ? prev : [...prev, id])),
    [],
  );

  // Daftar kelas hanya bersumber dari master kelas agar kelas yang dihapus
  // tidak muncul kembali dari data pengguna/siswa.
  const kelasList = useMemo(
    () => Array.from(new Set(masterKelas)).sort(),
    [masterKelas],
  );


  const value: Store = {
    currentUser,
    login,
    logout,
    users,
    setUsers,
    masterKelas,
    setMasterKelas,
    kelasList,
    siswa,
    setSiswa,
    jadwal,
    setJadwal,
    tamu,
    setTamu,
    pelanggaran,
    setPelanggaran,
    izin,
    setIzin,
    izinGuru,
    setIzinGuru,
    pemberitahuanBk,
    setPemberitahuanBk,
    saranOrtu,
    setSaranOrtu,
    tataTertib,
    setTataTertib,
    pengumuman,
    setPengumuman,
    pengumumanHistori,
    setPengumumanHistori,
    jadwalPelajaran,
    setJadwalPelajaran,
    jadwalMengajar,
    setJadwalMengajar,
    tautan,
    setTautan,
    dapodik,
    setDapodik,
    driveTamuUrl,
    setDriveTamuUrl,
    driveIzinGuruUrl,
    setDriveIzinGuruUrl,
    driveSuratBkUrl,
    setDriveSuratBkUrl,
    driveSaranUrl,
    prestasi,
    setPrestasi,
    drivePrestasiUrl,
    setDrivePrestasiUrl,
    setDriveSaranUrl,
    dismissedNotif,
    dismissNotif,
    dbStatus,
    spreadsheetId,
    setSpreadsheetId,
    reloadDatabase,
    backupDatabase,
    restoreDatabase,


  };

  return <SipContext.Provider value={value}>{children}</SipContext.Provider>;
}

export function useSip() {
  const ctx = useContext(SipContext);
  if (!ctx) throw new Error("useSip harus dipakai di dalam SipProvider");
  return ctx;
}
