/* global React */
// ============================================
// Sample data + central state hook
// ============================================

const { useState, useEffect, useRef, useCallback, useMemo, createContext, useContext } = React;

// --- Constants ---
const STATUS = {
  pending_director: { label: 'รอ ผอ. เกษียณ', short: 'รอเกษียณ', color: 'pending_director' },
  director_signed: { label: 'ผอ. ลงนามแล้ว', short: 'ลงนามแล้ว', color: 'director_signed' },
  assigned: { label: 'มอบหมายแล้ว', short: 'มอบหมายแล้ว', color: 'assigned' },
  sent_to_teacher: { label: 'ส่งครูแล้ว', short: 'ส่งครู', color: 'sent_to_teacher' },
  archived: { label: 'จัดเก็บ', short: 'จัดเก็บ', color: 'archived' },
};

const STATUS_ORDER = ['pending_director', 'director_signed', 'assigned', 'sent_to_teacher', 'archived'];

// --- Users ---
const USERS = {
  u_admin: { id: 'u_admin', name: 'นายอดิศักดิ์ ศรีบุญเรือง', role: 'ผู้ดูแลระบบ', initial: 'อด' },
  u_clerk: { id: 'u_clerk', name: 'คุณนภัสวรรณ พิมพ์ทอง', role: 'เจ้าหน้าที่ธุรการ', initial: 'นภ' },
  u_director: { id: 'u_director', name: 'นายสมพงษ์ ไชยมงคล', role: 'ผู้อำนวยการโรงเรียน', initial: 'สพ' },
  u_system: { id: 'u_system', name: 'ระบบ', role: 'อัตโนมัติ', initial: 'SYS' },
};

// --- Role metadata ---
const ROLE_LABEL = {
  admin: 'ผู้ดูแลระบบ',
  clerk: 'เจ้าหน้าที่ธุรการ',
  director: 'ผู้อำนวยการ',
  teacher: 'ครู / บุคลากร',
};

// --- Urgency / ชั้นความเร็วหนังสือราชการ (เรียงจากเบาไปหนัก) ---
const URGENCY = {
  normal:      { label: 'ปกติ',       rank: 0 },
  express:     { label: 'ด่วน',       rank: 1 },
  urgent:      { label: 'ด่วนมาก',    rank: 2 },
  most_urgent: { label: 'ด่วนที่สุด', rank: 3 },
};
const URGENCY_ORDER = ['normal', 'express', 'urgent', 'most_urgent'];
function isUrgent(u) { return !!u && u !== 'normal'; }
function urgencyRank(u) { return (URGENCY[u] && URGENCY[u].rank) || 0; }

// สถานะกำหนดส่ง: overdue (เลยกำหนด) / soon (<7วัน) / ok / null (ไม่มีกำหนด/จัดเก็บแล้ว)
function dueInfo(dueDate, status) {
  if (!dueDate || status === 'archived') return null;
  const ms = new Date(dueDate) - new Date();
  const day = 86400000;
  if (ms < 0) { const d = Math.max(1, Math.ceil(-ms / day)); return { kind: 'overdue', days: d, label: 'เลยกำหนด ' + d + ' วัน' }; }
  const left = Math.ceil(ms / day);
  if (left <= 7) return { kind: 'soon', days: left, label: left <= 1 ? 'ครบกำหนดเร็วๆ นี้' : 'เหลือ ' + left + ' วัน' };
  return { kind: 'ok', days: left, label: 'เหลือ ' + left + ' วัน' };
}

// --- Login accounts (prototype only — demo credentials) ---
const ACCOUNTS = [
  { username: 'admin',    password: 'admin123', userId: 'u_admin',    role: 'admin',    defaultView: 'admin_overview' },
  { username: 'clerk',    password: '1234',     userId: 'u_clerk',    role: 'clerk',    defaultView: 'dashboard' },
  { username: 'director', password: '1234',     userId: 'u_director', role: 'director', defaultView: 'dashboard' },
  { username: 'teacher',  password: '1234',     userId: 't_02',       role: 'teacher',  defaultView: 'teacher_tasks' },
];

// landing view for each role (used when creating login accounts)
function defaultViewForRole(role) {
  return role === 'admin' ? 'admin_overview'
    : role === 'teacher' ? 'teacher_tasks'
    : 'dashboard';
}
const NEW_USER_PASSWORD = '1234'; // default password for accounts the admin creates

// --- Manageable user accounts for the admin backend ---
function buildSysUsers() {
  return [
    { id: 'u_admin',    name: 'นายอดิศักดิ์ ศรีบุญเรือง', username: 'admin',    role: 'admin',    initial: 'อด', status: 'active',    lastLogin: daysAgo(0, 8, 2) },
    { id: 'u_clerk',    name: 'คุณนภัสวรรณ พิมพ์ทอง',    username: 'clerk',    role: 'clerk',    initial: 'นภ', status: 'active',    lastLogin: daysAgo(0, 8, 41) },
    { id: 'u_director', name: 'นายสมพงษ์ ไชยมงคล',       username: 'director', role: 'director', initial: 'สพ', status: 'active',    lastLogin: daysAgo(1, 16, 12) },
    { id: 't_02',       name: 'อ.วีรชัย ทองดี',           username: 'teacher',  role: 'teacher',  initial: 'วร', status: 'active',    lastLogin: daysAgo(2, 9, 30) },
    { id: 't_01',       name: 'อ.สุภาพร แก้วประดิษฐ์',    username: 'supaporn', role: 'teacher',  initial: 'สภ', status: 'active',    lastLogin: daysAgo(3, 10, 15) },
    { id: 't_07',       name: 'อ.จันทร์เพ็ญ บุญรอด',      username: 'janpen',   role: 'teacher',  initial: 'จพ', status: 'suspended', lastLogin: daysAgo(21, 11, 0) },
  ];
}

const TEACHERS = [
  { id: 't_01', name: 'อ.สุภาพร แก้วประดิษฐ์', group: 'หัวหน้ากลุ่มสาระวิทยาศาสตร์', initial: 'สภ' },
  { id: 't_02', name: 'อ.วีรชัย ทองดี', group: 'รองผู้อำนวยการฝ่ายวิชาการ', initial: 'วร' },
  { id: 't_03', name: 'อ.พรพิมล ศรีสุข', group: 'หัวหน้ากลุ่มสาระภาษาไทย', initial: 'พพ' },
  { id: 't_04', name: 'อ.ธนกฤต ใจดี', group: 'หัวหน้ากลุ่มสาระคณิตศาสตร์', initial: 'ธน' },
  { id: 't_05', name: 'อ.มณีวรรณ บุญมา', group: 'หัวหน้ากลุ่มสาระสังคมศึกษา', initial: 'มณ' },
  { id: 't_06', name: 'อ.อรรถพล สมบูรณ์', group: 'งานพัสดุและการเงิน', initial: 'อพ' },
  { id: 't_07', name: 'อ.จันทร์เพ็ญ บุญรอด', group: 'งานบุคคล', initial: 'จพ' },
  { id: 't_08', name: 'อ.ปิยะพงษ์ ก้อนทอง', group: 'หัวหน้ากลุ่มสาระภาษาต่างประเทศ', initial: 'ปย' },
  { id: 't_09', name: 'อ.ศิริพร ทองคำ', group: 'งานกิจการนักเรียน', initial: 'ศพ' },
  { id: 't_10', name: 'อ.ณัฐวัฒน์ พลอยแก้ว', group: 'หัวหน้ากลุ่มสาระศิลปะ', initial: 'ณว' },
];

// --- Thai date formatting (พ.ศ.) ---
const THAI_MONTHS = ['ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'];
const THAI_MONTHS_FULL = ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน','กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'];

function formatThaiDate(iso, opts = {}) {
  if (!iso) return '—';
  const d = new Date(iso);
  if (isNaN(d)) return '—';
  const day = d.getDate();
  const month = opts.full ? THAI_MONTHS_FULL[d.getMonth()] : THAI_MONTHS[d.getMonth()];
  const year = d.getFullYear() + 543;
  if (opts.withTime) {
    const hh = String(d.getHours()).padStart(2, '0');
    const mm = String(d.getMinutes()).padStart(2, '0');
    return `${day} ${month} ${year} ${hh}:${mm} น.`;
  }
  return `${day} ${month} ${year}`;
}

function relativeThai(iso) {
  const d = new Date(iso);
  const now = new Date();
  const diffMs = now - d;
  const diffMin = Math.floor(diffMs / 60000);
  if (diffMin < 1) return 'เมื่อสักครู่';
  if (diffMin < 60) return `${diffMin} นาทีที่แล้ว`;
  const diffHr = Math.floor(diffMin / 60);
  if (diffHr < 24) return `${diffHr} ชม.ที่แล้ว`;
  const diffDay = Math.floor(diffHr / 24);
  if (diffDay < 7) return `${diffDay} วันที่แล้ว`;
  return formatThaiDate(iso);
}

// helper: ISO date n days ago at given hour
function daysAgo(n, h = 9, m = 0) {
  const d = new Date();
  d.setDate(d.getDate() - n);
  d.setHours(h, m, 0, 0);
  return d.toISOString();
}

// --- Sample documents ---
function buildDocs() {
  return [
    {
      id: 'd001',
      docNumber: '68-042',
      refNumber: 'ศธ 04218/ว 1247',
      receivedDate: daysAgo(0, 9, 12),
      docDate: daysAgo(2, 10, 0),
      subject: 'การจัดสรรงบประมาณรายจ่ายประจำปีงบประมาณ พ.ศ. 2568 งบลงทุน รายการครุภัณฑ์การศึกษา',
      from: 'สำนักงานเขตพื้นที่การศึกษามัธยมศึกษาอุบลราชธานี อำนาจเจริญ',
      fromShort: 'สพม.อุบลฯ อำนาจฯ',
      urgency: 'urgent',
      clerkNote: 'เรียน ท่าน ผอ. โปรดพิจารณาเกษียณหนังสือเพื่อมอบหมายฝ่ายพัสดุดำเนินการตามกำหนด ภายในวันที่ 31 พ.ค. 68',
      directorNote: '',
      status: 'pending_director',
      assignedTo: [],
      dueDate: daysAgo(-7, 16, 30),
      log: [
        { at: daysAgo(0, 9, 12), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือจากเว็บเขตพื้นที่ ออกเลขรับ 68-042' }
      ],
      createdAt: daysAgo(0, 9, 12),
    },
    {
      id: 'd002',
      docNumber: '68-041',
      refNumber: 'ศธ 04218/ว 1241',
      receivedDate: daysAgo(0, 8, 45),
      docDate: daysAgo(3, 14, 0),
      subject: 'ขอเชิญประชุมเชิงปฏิบัติการการขับเคลื่อนหลักสูตรฐานสมรรถนะระดับเขตพื้นที่',
      from: 'สำนักงานเขตพื้นที่การศึกษามัธยมศึกษาอุบลราชธานี อำนาจเจริญ',
      fromShort: 'สพม.อุบลฯ อำนาจฯ',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. โปรดพิจารณามอบหมายผู้แทนเข้าร่วมประชุม',
      directorNote: '',
      status: 'pending_director',
      assignedTo: [],
      dueDate: daysAgo(-5, 16, 30),
      log: [
        { at: daysAgo(0, 8, 45), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือทางอีเมล ออกเลขรับ 68-041' }
      ],
      createdAt: daysAgo(0, 8, 45),
    },
    {
      id: 'd003',
      docNumber: '68-040',
      refNumber: 'ศธ 04002/4729',
      receivedDate: daysAgo(1, 10, 20),
      docDate: daysAgo(4, 9, 0),
      subject: 'การสำรวจข้อมูลครูและบุคลากรทางการศึกษา ปีการศึกษา 2568',
      from: 'สำนักงานคณะกรรมการการศึกษาขั้นพื้นฐาน',
      fromShort: 'สพฐ.',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. เพื่อโปรดมอบหมายงานบุคคลดำเนินการ',
      directorNote: 'มอบ อ.จันทร์เพ็ญ บุญรอด งานบุคคล ดำเนินการตามแบบสำรวจที่แนบ และส่งกลับภายในกำหนด',
      status: 'director_signed',
      assignedTo: [],
      dueDate: daysAgo(-4, 16, 30),
      log: [
        { at: daysAgo(1, 10, 20), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือ ออกเลขรับ 68-040' },
        { at: daysAgo(0, 15, 30), by: 'u_director', from: 'pending_director', to: 'director_signed', note: 'ลงนามและเกษียณหนังสือ พร้อมระบุผู้รับผิดชอบ' },
      ],
      createdAt: daysAgo(1, 10, 20),
    },
    {
      id: 'd004',
      docNumber: '68-039',
      refNumber: 'ศธ 04218/ว 1198',
      receivedDate: daysAgo(2, 9, 0),
      docDate: daysAgo(5, 11, 0),
      subject: 'การประเมินคุณภาพภายในสถานศึกษา ปีการศึกษา 2567',
      from: 'สำนักงานเขตพื้นที่การศึกษามัธยมศึกษาอุบลราชธานี อำนาจเจริญ',
      fromShort: 'สพม.อุบลฯ อำนาจฯ',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. โปรดพิจารณามอบหมายฝ่ายวิชาการ',
      directorNote: 'มอบ อ.วีรชัย ทองดี รองฝ่ายวิชาการ ดำเนินการประเมินตามแนวทางที่กำหนด รายงานภายใน 15 มิ.ย.',
      status: 'assigned',
      assignedTo: ['t_02'],
      dueDate: daysAgo(-22, 16, 30),
      log: [
        { at: daysAgo(2, 9, 0), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือ ออกเลขรับ 68-039' },
        { at: daysAgo(1, 14, 12), by: 'u_director', from: 'pending_director', to: 'director_signed', note: 'ลงนามและเกษียณหนังสือ' },
        { at: daysAgo(1, 14, 14), by: 'u_director', from: 'director_signed', to: 'assigned', note: 'มอบหมาย อ.วีรชัย ทองดี' },
      ],
      createdAt: daysAgo(2, 9, 0),
    },
    {
      id: 'd005',
      docNumber: '68-038',
      refNumber: 'ศธ 04218/ว 1175',
      receivedDate: daysAgo(3, 10, 30),
      docDate: daysAgo(6, 14, 0),
      subject: 'ขอความอนุเคราะห์ตอบแบบสอบถามการพัฒนาสมรรถนะดิจิทัลของครู',
      from: 'สำนักงานเขตพื้นที่การศึกษามัธยมศึกษาอุบลราชธานี อำนาจเจริญ',
      fromShort: 'สพม.อุบลฯ อำนาจฯ',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. ส่งครูประจำการตอบแบบสอบถามทุกคน',
      directorNote: 'แจ้งครูทุกคนตอบแบบสอบถามภายใน 30 พ.ค. 68 มอบ อ.วีรชัย ติดตาม',
      status: 'sent_to_teacher',
      assignedTo: ['t_02', 't_03', 't_01', 't_04'],
      dueDate: daysAgo(-6, 16, 30),
      log: [
        { at: daysAgo(3, 10, 30), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือ' },
        { at: daysAgo(2, 16, 0), by: 'u_director', from: 'pending_director', to: 'director_signed', note: 'ลงนาม' },
        { at: daysAgo(2, 16, 2), by: 'u_director', from: 'director_signed', to: 'assigned', note: 'มอบหมาย 4 ท่าน' },
        { at: daysAgo(2, 16, 30), by: 'u_clerk', from: 'assigned', to: 'sent_to_teacher', note: 'ส่ง PDF ถึงผู้รับมอบหมายและแจ้งเตือนผ่าน Telegram' },
      ],
      createdAt: daysAgo(3, 10, 30),
    },
    {
      id: 'd006',
      docNumber: '68-037',
      refNumber: 'อบ 0023.4/ว 891',
      receivedDate: daysAgo(4, 9, 0),
      docDate: daysAgo(7, 10, 0),
      subject: 'การฝึกอบรมการป้องกันและระงับอัคคีภัยในสถานศึกษา',
      from: 'สำนักงานป้องกันและบรรเทาสาธารณภัยจังหวัดอุบลราชธานี',
      fromShort: 'สำนักงาน ปภ.อุบลฯ',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. โปรดมอบหมายตัวแทนเข้าร่วม',
      directorNote: 'มอบ อ.อรรถพล สมบูรณ์ เข้าร่วมอบรม',
      status: 'archived',
      assignedTo: ['t_06'],
      dueDate: daysAgo(-1, 16, 30),
      log: [
        { at: daysAgo(4, 9, 0), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือ' },
        { at: daysAgo(3, 11, 0), by: 'u_director', from: 'pending_director', to: 'director_signed', note: 'ลงนาม' },
        { at: daysAgo(3, 11, 5), by: 'u_director', from: 'director_signed', to: 'assigned', note: 'มอบหมาย อ.อรรถพล' },
        { at: daysAgo(3, 14, 0), by: 'u_clerk', from: 'assigned', to: 'sent_to_teacher', note: 'ส่ง PDF ให้ครู' },
        { at: daysAgo(0, 17, 0), by: 'u_clerk', from: 'sent_to_teacher', to: 'archived', note: 'ปิดงานและจัดเก็บเข้าระบบ' },
      ],
      createdAt: daysAgo(4, 9, 0),
      archivedAt: daysAgo(0, 17, 0),
    },
    {
      id: 'd007',
      docNumber: '68-036',
      refNumber: 'ศธ 04218/ว 1132',
      receivedDate: daysAgo(5, 13, 0),
      docDate: daysAgo(8, 11, 0),
      subject: 'การคัดเลือกครูดีในดวงใจ ครั้งที่ 22 ประจำปี พ.ศ. 2568',
      from: 'สำนักงานเขตพื้นที่การศึกษามัธยมศึกษาอุบลราชธานี อำนาจเจริญ',
      fromShort: 'สพม.อุบลฯ อำนาจฯ',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. เพื่อโปรดทราบและประชาสัมพันธ์',
      directorNote: 'แจ้งครูทุกท่านทราบ ผู้สนใจส่งใบสมัครภายในวันที่ 10 มิ.ย. 68',
      status: 'archived',
      assignedTo: ['t_07'],
      dueDate: daysAgo(-18, 16, 30),
      log: [
        { at: daysAgo(5, 13, 0), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือ' },
        { at: daysAgo(4, 10, 0), by: 'u_director', from: 'pending_director', to: 'director_signed', note: 'ลงนาม' },
        { at: daysAgo(4, 10, 5), by: 'u_director', from: 'director_signed', to: 'assigned', note: 'มอบหมาย อ.จันทร์เพ็ญ' },
        { at: daysAgo(4, 12, 0), by: 'u_clerk', from: 'assigned', to: 'sent_to_teacher', note: 'ส่ง PDF ให้ครู' },
        { at: daysAgo(1, 15, 0), by: 'u_clerk', from: 'sent_to_teacher', to: 'archived', note: 'จัดเก็บ' },
      ],
      createdAt: daysAgo(5, 13, 0),
      archivedAt: daysAgo(1, 15, 0),
    },
    {
      id: 'd008',
      docNumber: '68-035',
      refNumber: 'ศธ 04002/ว 4612',
      receivedDate: daysAgo(6, 9, 0),
      docDate: daysAgo(10, 14, 0),
      subject: 'การจัดทำรายงานผลการดำเนินงาน ตามแผนปฏิบัติการประจำปี 2567',
      from: 'สำนักงานคณะกรรมการการศึกษาขั้นพื้นฐาน',
      fromShort: 'สพฐ.',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. มอบหมายฝ่ายแผนงาน',
      directorNote: 'มอบ อ.วีรชัย จัดทำรายงานและตรวจสอบความถูกต้องก่อนนำเสนอ',
      status: 'sent_to_teacher',
      assignedTo: ['t_02'],
      dueDate: daysAgo(-8, 16, 30),
      log: [
        { at: daysAgo(6, 9, 0), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือ' },
        { at: daysAgo(5, 11, 0), by: 'u_director', from: 'pending_director', to: 'director_signed', note: 'ลงนาม' },
        { at: daysAgo(5, 11, 5), by: 'u_director', from: 'director_signed', to: 'assigned', note: 'มอบหมาย อ.วีรชัย' },
        { at: daysAgo(5, 13, 0), by: 'u_clerk', from: 'assigned', to: 'sent_to_teacher', note: 'ส่ง PDF ให้ครู' },
      ],
      createdAt: daysAgo(6, 9, 0),
    },
    {
      id: 'd009',
      docNumber: '68-034',
      refNumber: 'อบ 51001/ว 245',
      receivedDate: daysAgo(7, 14, 0),
      docDate: daysAgo(9, 10, 0),
      subject: 'ขอความร่วมมือประชาสัมพันธ์การรับสมัครสมาชิกสภาเด็กและเยาวชน',
      from: 'องค์การบริหารส่วนจังหวัดอุบลราชธานี',
      fromShort: 'อบจ.อุบลฯ',
      urgency: 'normal',
      clerkNote: 'เรียน ท่าน ผอ. โปรดประชาสัมพันธ์',
      directorNote: 'แจ้ง อ.ศิริพร งานกิจการนักเรียนประชาสัมพันธ์',
      status: 'archived',
      assignedTo: ['t_09'],
      dueDate: daysAgo(-3, 16, 30),
      log: [
        { at: daysAgo(7, 14, 0), by: 'u_clerk', from: null, to: 'pending_director', note: 'รับหนังสือ' },
        { at: daysAgo(6, 10, 0), by: 'u_director', from: 'pending_director', to: 'director_signed', note: 'ลงนาม' },
        { at: daysAgo(6, 10, 5), by: 'u_director', from: 'director_signed', to: 'assigned', note: 'มอบหมาย อ.ศิริพร' },
        { at: daysAgo(6, 13, 0), by: 'u_clerk', from: 'assigned', to: 'sent_to_teacher', note: 'ส่ง PDF ให้ครู' },
        { at: daysAgo(2, 16, 0), by: 'u_clerk', from: 'sent_to_teacher', to: 'archived', note: 'จัดเก็บ' },
      ],
      createdAt: daysAgo(7, 14, 0),
      archivedAt: daysAgo(2, 16, 0),
    },
  ];
}

// --- System settings (editable by admin) ---
function buildSettings() {
  return {
    schoolName: 'โรงเรียนวัดบ้านกะชาย',
    academicYear: '2569',
    docNumberFormat: '68-NNN (กำหนดเอง)',
    dateFormat: 'thai',   // 'thai' (พ.ศ.) | 'inter' (ค.ศ.)
    language: 'th',       // 'th' | 'en'
    parentAgency: 'สพม.อุบลฯ อำนาจฯ',
  };
}

// --- localStorage persistence (so created users / settings survive reload) ---
const LS_PREFIX = 'kachai.v1.';
function lsLoad(key, fallback) {
  try {
    const raw = localStorage.getItem(LS_PREFIX + key);
    if (raw == null) return typeof fallback === 'function' ? fallback() : fallback;
    return JSON.parse(raw);
  } catch (e) {
    return typeof fallback === 'function' ? fallback() : fallback;
  }
}
function lsSave(key, value) {
  try { localStorage.setItem(LS_PREFIX + key, JSON.stringify(value)); } catch (e) { /* ignore quota / privacy mode */ }
}

// --- Central store ---
const StoreCtx = createContext(null);

// true when a real Supabase backend is configured (see supabase-config.js)
const SB = (typeof window !== 'undefined' && window.DB && window.DB.enabled) ? window.DB : null;

function StoreProvider({ children }) {
  const [docs, setDocs] = useState(buildDocs);
  const [currentUser, setCurrentUser] = useState(null); // null = logged out
  const [accounts, setAccounts] = useState(() => lsLoad('accounts', () => ACCOUNTS.map(a => ({ ...a })))); // persisted; passwords change-able
  const [sysUsers, setSysUsers] = useState(() => lsLoad('sysUsers', buildSysUsers));
  const [settings, setSettings] = useState(() => lsLoad('settings', buildSettings));
  // while connected to Supabase we restore the session before showing the UI
  const [booting, setBooting] = useState(!!SB);

  // persist the editable slices to localStorage ONLY in mockup mode
  // (when connected to Supabase the database is the source of truth)
  useEffect(() => { if (!SB) lsSave('accounts', accounts); }, [accounts]);
  useEffect(() => { if (!SB) lsSave('sysUsers', sysUsers); }, [sysUsers]);
  useEffect(() => { if (!SB) lsSave('settings', settings); }, [settings]);

  // keep a live id→user index so getUserById() can resolve real Supabase
  // profiles (UUID ids) in the audit timeline, not just the mockup users
  useEffect(() => {
    SYS_USER_INDEX = Object.fromEntries((sysUsers || []).map(u => [u.id, u]));
  }, [sysUsers]);

  // pull the editable data from Supabase into local state
  const refresh = useCallback(async () => {
    if (!SB) return;
    try {
      const d = await SB.loadAll();
      setDocs(d.docs);
      setSysUsers(d.sysUsers);
      SYS_USER_INDEX = Object.fromEntries((d.sysUsers || []).map(u => [u.id, u]));
      if (d.settings) setSettings(d.settings);
      if (d.notifications) setNotifications(d.notifications);
      if (d.announcements) setAnnouncements(d.announcements);
    } catch (e) { console.error('[kachai] loadAll failed', e); }
  }, []);

  // on mount (connected mode): restore session + load data
  useEffect(() => {
    if (!SB) return;
    let alive = true;
    (async () => {
      try {
        const prof = await SB.currentProfile();
        if (alive && prof) {
          setCurrentUser({ ...prof, role: prof.role });
          setRole(prof.role);
          setActiveView(prof.defaultView);
          await refresh();
        }
      } catch (e) { console.error('[kachai] session restore failed', e); }
      if (alive) setBooting(false);
    })();
    return () => { alive = false; };
  }, [refresh]);

  // ปุ่ม Esc → ปิด overlay/popover/drawer/เมนูมือถือ (กันจอทึบค้าง)
  useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'Escape') {
        setMobileNavOpen(false);
        setNotifPopOpen(false);
        setDrawerDocId(null);
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  // ขยายจอจากมือถือเป็นเดสก์ท็อป → ปิดเมนูแฮมเบอร์เกอร์อัตโนมัติ
  useEffect(() => {
    const onResize = () => { if (window.innerWidth > 900) setMobileNavOpen(false); };
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  const [role, setRole] = useState('clerk'); // admin | clerk | director | teacher
  const [activeView, setActiveView] = useState('dashboard');
  const [drawerDocId, setDrawerDocId] = useState(null);
  const [drawerTab, setDrawerTab] = useState('detail'); // detail | sign | assign | audit
  const [toasts, setToasts] = useState([]);
  const [notifPopOpen, setNotifPopOpen] = useState(false);
  const [mobileNavOpen, setMobileNavOpen] = useState(false); // เมนูแฮมเบอร์เกอร์บนมือถือ
  const [notifications, setNotifications] = useState(seedNotifications);
  const [announcements, setAnnouncements] = useState([]);

  const toast = useCallback((msg, kind = 'success') => {
    const id = `t_${Date.now()}_${Math.random()}`;
    setToasts(prev => [...prev, { id, msg, kind }]);
    setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 3200);
  }, []);

  const updateDoc = useCallback((id, patch, logEntry) => {
    // optimistic local update (keeps UI reactive in both modes)
    setDocs(prev => prev.map(d => {
      if (d.id !== id) return d;
      const next = { ...d, ...patch };
      if (logEntry) {
        next.log = [...d.log, { ...logEntry, at: new Date().toISOString() }];
      }
      return next;
    }));
    if (SB) {
      return (async () => {
        await SB.updateDocument(id, patch);
        if (patch.assignedTo !== undefined) await SB.setAssignees(id, patch.assignedTo);
        if (logEntry) await SB.addLog(id, (currentUser && currentUser.id) || null, logEntry.from, logEntry.to, logEntry.note);
      })().catch(e => console.error('[kachai] updateDoc', e));
    }
    return Promise.resolve();
  }, [currentUser]);

  const addDoc = useCallback((doc, file, attachments) => {
    const atts = attachments || [];
    if (SB) {
      (async () => {
        const res = await SB.insertDocument(doc, (currentUser && currentUser.id) || null);
        if (res.ok) {
          await SB.addLog(res.doc.id, (currentUser && currentUser.id) || null, null, 'pending_director', `รับหนังสือ ออกเลขรับ ${doc.docNumber}`);
          if (file) {
            const up = await SB.uploadDocFile(res.doc.id, 'original', file);
            if (!up.ok) { console.error('[kachai] uploadDocFile', up.error); toast('บันทึกหนังสือแล้ว แต่อัปโหลดไฟล์ PDF ไม่สำเร็จ: ' + up.error, 'amber'); }
          }
          for (const att of atts) {
            const up = await SB.uploadDocFile(res.doc.id, 'attachment', att);
            if (!up.ok) console.error('[kachai] upload attachment', up.error);
          }
          await refresh();
        }
      })().catch(e => console.error('[kachai] addDoc', e));
      return;
    }
    // mockup: keep in-memory blob URLs so files can still be previewed/downloaded
    const files = [];
    if (file) files.push({ kind: 'original', url: URL.createObjectURL(file), name: file.name });
    atts.forEach(a => files.push({ kind: 'attachment', url: URL.createObjectURL(a), name: a.name }));
    setDocs(prev => [{ ...doc, files, log: [{ at: new Date().toISOString(), by: 'u_clerk', from: null, to: 'pending_director', note: `รับหนังสือ ออกเลขรับ ${doc.docNumber}` }] }, ...prev]);
  }, [currentUser, refresh, toast]);

  const deleteDoc = useCallback((id) => {
    const doc = docs.find(d => d.id === id);
    setDocs(prev => prev.filter(d => d.id !== id));
    setDrawerDocId(prev => (prev === id ? null : prev));
    if (SB) {
      const paths = ((doc && doc.files) || []).map(f => f.storagePath).filter(Boolean);
      SB.deleteDocument(id, paths).then(r => {
        if (!r.ok) { console.error('[kachai] deleteDocument', r.error); toast('ลบหนังสือไม่สำเร็จ: ' + r.error, 'amber'); refresh(); }
      }).catch(e => { console.error('[kachai] deleteDocument', e); refresh(); });
    }
  }, [docs, refresh, toast]);

  // upload an extra file (e.g. the generated 'signed' / 'final' PDF) for a doc
  const addDocFile = useCallback(async (docId, kind, file) => {
    if (SB) {
      const up = await SB.uploadDocFile(docId, kind, file);
      if (up.ok) await refresh();
      return up;
    }
    // mockup: attach an in-memory blob URL
    const url = URL.createObjectURL(file);
    setDocs(prev => prev.map(d => d.id === docId
      ? { ...d, files: [...((d.files) || []), { kind, url, name: file.name }] }
      : d));
    return { ok: true };
  }, [refresh]);

  // resolve a URL for a specific file object (เช่น เอกสารแนบแต่ละไฟล์)
  const getStorageUrl = useCallback(async (f) => {
    if (!f) return null;
    if (SB) return f.storagePath ? await SB.signedUrl(f.storagePath) : null;
    return f.url || null;
  }, []);

  // resolve a viewable/downloadable URL for a doc's file of a given kind
  // (signed URL in Supabase mode, in-memory blob URL in mockup mode)
  const getDocFileUrl = useCallback(async (doc, kind = 'original') => {
    const files = (doc && doc.files) || [];
    const f = [...files].reverse().find(x => x.kind === kind);
    if (!f) return null;
    if (SB) return f.storagePath ? await SB.signedUrl(f.storagePath) : null;
    return f.url || null;
  }, []);

  const openDoc = useCallback((id, tab = 'detail') => {
    setDrawerDocId(id);
    setDrawerTab(tab);
  }, []);

  const addNotif = useCallback((n) => {
    setNotifications(prev => [{ id: `n_${Date.now()}_${Math.random()}`, at: new Date().toISOString(), unread: true, ...n }, ...prev]);
  }, []);

  const markAllRead = useCallback(() => {
    setNotifications(prev => prev.map(n => ({ ...n, unread: false })));
  }, []);

  // ---- Announcements (แจ้งประชุม/นัดหมาย) ----
  const addAnnouncement = useCallback(async (a) => {
    if (SB) {
      const res = await SB.insertAnnouncement(a, (currentUser && currentUser.id) || null);
      if (res.ok) setAnnouncements(prev => [...prev, res.announcement].sort((x, y) => (x.meetingDate || '').localeCompare(y.meetingDate || '')));
      return res;
    }
    const id = `an_${Date.now()}`;
    setAnnouncements(prev => [...prev, { id, ...a, createdBy: currentUser && currentUser.id, createdAt: new Date().toISOString() }]);
    return { ok: true };
  }, [currentUser]);

  const editAnnouncement = useCallback(async (id, patch) => {
    setAnnouncements(prev => prev.map(a => a.id === id ? { ...a, ...patch } : a));
    if (SB) {
      const res = await SB.updateAnnouncement(id, patch);
      if (!res.ok) { toast('แก้ไขประกาศไม่สำเร็จ: ' + res.error, 'amber'); refresh(); }
      return res;
    }
    return { ok: true };
  }, [refresh, toast]);

  const removeAnnouncement = useCallback(async (id) => {
    setAnnouncements(prev => prev.filter(a => a.id !== id));
    if (SB) {
      const res = await SB.deleteAnnouncement(id);
      if (!res.ok) { toast('ลบประกาศไม่สำเร็จ: ' + res.error, 'amber'); refresh(); }
      return res;
    }
    return { ok: true };
  }, [refresh, toast]);

  const login = useCallback(async (username, password) => {
    if (SB) {
      const res = await SB.signIn(username, password);
      if (!res.ok) return res;
      const prof = res.profile || {};
      setCurrentUser({ ...prof, role: prof.role });
      setRole(prof.role);
      setActiveView(prof.defaultView || 'dashboard');
      await refresh();
      return { ok: true };
    }
    // ---- mockup ----
    const acct = accounts.find(a => a.username === username.trim() && a.password === password);
    if (!acct) return { ok: false, error: 'ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง' };
    // resolve the display profile. sysUsers is the editable/persisted source of
    // truth (reflects admin edits), so prefer it over the static USERS/TEACHERS.
    const profile = sysUsers.find(su => su.id === acct.userId)
      || USERS[acct.userId]
      || TEACHERS.find(t => t.id === acct.userId)
      || { name: 'ผู้ใช้งาน', role: '', initial: '?' };
    // acct spread LAST so its role key ('admin'/'clerk'/…) wins over the
    // profile's human-readable role title; keep the title as roleTitle.
    setCurrentUser({ ...profile, roleTitle: profile.role, ...acct });
    setRole(acct.role);
    setActiveView(acct.defaultView);
    setSysUsers(prev => prev.map(u => u.id === acct.userId ? { ...u, lastLogin: new Date().toISOString() } : u));
    return { ok: true };
  }, [accounts, sysUsers, refresh]);

  const changePassword = useCallback(async (currentPw, newPw) => {
    if (!currentUser) return { ok: false, error: 'กรุณาเข้าสู่ระบบก่อน' };
    if (SB) {
      // verify the current password by re-authenticating, then update
      const re = await SB.signIn(currentUser.username, currentPw);
      if (!re.ok) return { ok: false, error: 'รหัสผ่านปัจจุบันไม่ถูกต้อง' };
      return await SB.changePassword(newPw);
    }
    // ---- mockup ----
    const acct = accounts.find(a => a.username === currentUser.username);
    if (!acct) return { ok: false, error: 'ไม่พบบัญชีผู้ใช้' };
    if (acct.password !== currentPw) return { ok: false, error: 'รหัสผ่านปัจจุบันไม่ถูกต้อง' };
    setAccounts(prev => prev.map(a => a.username === currentUser.username ? { ...a, password: newPw } : a));
    return { ok: true };
  }, [accounts, currentUser]);

  const logout = useCallback(async () => {
    if (SB) { try { await SB.signOut(); } catch (e) {} }
    setCurrentUser(null);
    setRole('clerk');
    setActiveView('dashboard');
    setNotifPopOpen(false);
    setDrawerDocId(null);
  }, []);

  const updateSysUser = useCallback((id, patch) => {
    // optimistic local update + keep the logged-in identity fresh
    setSysUsers(prev => prev.map(u => u.id === id ? { ...u, ...patch } : u));
    setCurrentUser(prev => (prev && prev.id === id) ? { ...prev, ...patch } : prev);
    if (SB) { SB.updateProfile(id, patch).catch(e => console.error('[kachai] updateProfile', e)); return; }
    // mockup: keep the matching login account in sync — or create one if this
    // user had none yet (e.g. a display-only seed user the admin just edited).
    setAccounts(prev => {
      const existing = prev.find(a => a.userId === id);
      if (existing) {
        return prev.map(a => {
          if (a.userId !== id) return a;
          const next = { ...a };
          if (patch.username !== undefined) next.username = patch.username;
          if (patch.role !== undefined) { next.role = patch.role; next.defaultView = defaultViewForRole(patch.role); }
          return next;
        });
      }
      if (patch.username) {
        const role = patch.role || 'teacher';
        return [...prev, { username: patch.username, password: NEW_USER_PASSWORD, userId: id, role, defaultView: defaultViewForRole(role) }];
      }
      return prev;
    });
  }, []);

  const deleteSysUser = useCallback((id) => {
    setSysUsers(prev => prev.filter(u => u.id !== id));
    if (SB) { SB.deleteProfile(id).catch(e => console.error('[kachai] deleteProfile', e)); return; }
    setAccounts(prev => prev.filter(a => a.userId !== id));
  }, []);

  const addSysUser = useCallback(async (u) => {
    if (SB) {
      // เรียก Edge Function 'create-user' (ใช้ service_role ฝั่งเซิร์ฟเวอร์)
      // ดู supabase/functions/create-user/index.ts + วิธี deploy ใน SETUP.md
      try {
        const emailDomain = (window.SUPABASE_CONFIG && window.SUPABASE_CONFIG.emailDomain) || 'kachai.local';
        const { data, error } = await SB.client.functions.invoke('create-user', {
          body: { ...u, password: NEW_USER_PASSWORD, emailDomain },
        });
        if (error) {
          // ดึงข้อความ error จาก response body ถ้ามี (FunctionsHttpError)
          let msg = error.message || 'สร้างผู้ใช้ไม่สำเร็จ';
          try { const j = await error.context.json(); if (j && j.error) msg = j.error; } catch (e) {}
          return { ok: false, error: msg };
        }
        if (!data || !data.ok) return { ok: false, error: (data && data.error) || 'สร้างผู้ใช้ไม่สำเร็จ' };
        setSysUsers(prev => [data.user, ...prev]);
        return { ok: true, user: data.user };
      } catch (e) {
        console.error('[kachai] create-user', e);
        return { ok: false, error: 'เรียกฟังก์ชันสร้างผู้ใช้ไม่สำเร็จ (ยัง deploy ฟังก์ชันหรือยัง?)' };
      }
    }
    const id = `u_${Date.now()}`;
    setSysUsers(prev => [{ id, status: 'active', lastLogin: null, ...u }, ...prev]);
    // create a real login account so the new user can sign in (default password)
    setAccounts(prev => [...prev, {
      username: u.username,
      password: NEW_USER_PASSWORD,
      userId: id,
      role: u.role,
      defaultView: defaultViewForRole(u.role),
    }]);
    return { ok: true };
  }, [toast]);

  const updateSettings = useCallback((patch) => {
    setSettings(prev => ({ ...prev, ...patch }));
    if (SB) SB.updateSettings(patch).catch(e => console.error('[kachai] updateSettings', e));
  }, []);

  const value = {
    docs, setDocs, updateDoc, addDoc, deleteDoc, getDocFileUrl, getStorageUrl, addDocFile,
    currentUser, login, logout, changePassword, booting, dataSource: SB ? 'supabase' : 'mockup',
    sysUsers, updateSysUser, addSysUser, deleteSysUser,
    settings, updateSettings,
    role, setRole,
    activeView, setActiveView,
    drawerDocId, setDrawerDocId, drawerTab, setDrawerTab, openDoc,
    toast, toasts,
    notifPopOpen, setNotifPopOpen,
    mobileNavOpen, setMobileNavOpen,
    notifications, addNotif, markAllRead,
    announcements, addAnnouncement, editAnnouncement, removeAnnouncement,
  };

  return React.createElement(StoreCtx.Provider, { value }, children);
}

function useStore() {
  const ctx = useContext(StoreCtx);
  if (!ctx) throw new Error('StoreProvider missing');
  return ctx;
}

// --- Seed notifications ---
function seedNotifications() {
  return [
    {
      id: 'n_001',
      at: daysAgo(0, 9, 12),
      unread: true,
      kind: 'new_doc',
      title: 'หนังสือรับใหม่ — เลข 68-042',
      desc: 'การจัดสรรงบประมาณรายจ่ายประจำปีงบประมาณ พ.ศ. 2568...',
      docId: 'd001',
      urgent: true,
    },
    {
      id: 'n_002',
      at: daysAgo(0, 8, 45),
      unread: true,
      kind: 'new_doc',
      title: 'หนังสือรับใหม่ — เลข 68-041',
      desc: 'ขอเชิญประชุมเชิงปฏิบัติการการขับเคลื่อนหลักสูตร...',
      docId: 'd002',
      urgent: false,
    },
    {
      id: 'n_003',
      at: daysAgo(0, 15, 30),
      unread: false,
      kind: 'director_signed',
      title: 'ผอ. เกษียณหนังสือ — เลข 68-040',
      desc: 'พร้อมส่งให้ครูผู้รับมอบหมาย',
      docId: 'd003',
    },
    {
      id: 'n_004',
      at: daysAgo(1, 14, 14),
      unread: false,
      kind: 'assigned',
      title: 'มอบหมายงานครู — เลข 68-039',
      desc: 'อ.วีรชัย ทองดี ได้รับมอบหมาย',
      docId: 'd004',
    },
  ];
}

// --- Helpers ---
function statusBadge(status) {
  const s = STATUS[status];
  if (!s) return null;
  return React.createElement('span', { className: `badge ${s.color}` },
    React.createElement('span', { className: 'dot' }),
    s.label
  );
}

// live index of real (Supabase) users, kept in sync by StoreProvider
let SYS_USER_INDEX = {};

function getUserById(id) {
  if (!id) return { name: 'ระบบ', role: '', initial: '·' };
  return SYS_USER_INDEX[id] || USERS[id] || TEACHERS.find(t => t.id === id) || { name: 'ไม่ทราบ', role: '', initial: '?' };
}

// expose globally
Object.assign(window, {
  useStore, StoreProvider, STATUS, STATUS_ORDER, USERS, TEACHERS, ACCOUNTS, ROLE_LABEL,
  URGENCY, URGENCY_ORDER, isUrgent, urgencyRank, dueInfo,
  formatThaiDate, relativeThai, daysAgo, statusBadge, getUserById, THAI_MONTHS, THAI_MONTHS_FULL,
});
