// data.jsx — initial state, helpers, palette
// Shared across the scheduling prototype.

const DOCTORS_INIT = [
  { id: 'd1', name: '林依儒', tone: '#f7d3dc', text: '#7a2540', dark: '#c75478' },
  { id: 'd2', name: '鐘小晴', tone: '#fbeac1', text: '#7a5318', dark: '#b88224' },
  { id: 'd3', name: '陳怡瑛', tone: '#d5ecd6', text: '#225b29', dark: '#3f8a45' },
  { id: 'd4', name: '方敬戎', tone: '#cfeaf0', text: '#1c5b66', dark: '#3a8a99' },
  { id: 'd5', name: '莊征祐', tone: '#fbdcc1', text: '#7a4318', dark: '#b86824' },
  { id: 'd6', name: '林博文', tone: '#dcd3f0', text: '#3d2a73', dark: '#6d54bf' },
  { id: 'd7', name: '吳宛凌', tone: '#d4ecea', text: '#1c5a55', dark: '#3a8a82' },
];

const SHIFTS_INIT = [
  { id: 'early', label: '早班', start: '09:00', end: '12:30', accent: '#f4c97b' },
  { id: 'mid',   label: '午班', start: '13:30', end: '17:00', accent: '#a3c5e0' },
  { id: 'late',  label: '晚班', start: '17:30', end: '21:00', accent: '#b9a1d9' },
];

// initial: closed Wed (weekday 3, Mon-first index = 2)
const WEEKLY_HOLIDAYS_INIT = [2];

// Week template: one row per weekday (0=Mon..6=Sun), shift -> doctorIds[]
// We populate a realistic mix.
const WEEK_TEMPLATE_INIT = {
  0: { early: ['d1','d2'], mid: ['d3','d4'], late: ['d5']      }, // Mon
  1: { early: ['d3','d5'], mid: ['d1','d6'], late: ['d2','d4'] }, // Tue
  2: { early: [],          mid: [],          late: []          }, // Wed (closed)
  3: { early: ['d2','d4'], mid: ['d5','d7'], late: ['d1','d3'] }, // Thu
  4: { early: ['d1','d6'], mid: ['d2','d3'], late: ['d4','d5'] }, // Fri
  5: { early: ['d5','d7'], mid: ['d1','d2','d4'], late: ['d3']  }, // Sat
  6: { early: ['d3','d4'], mid: ['d5','d6'], late: ['d1']       }, // Sun
};

// Exceptional holidays (date strings 'YYYY-MM-DD') — start empty
const SPECIAL_HOLIDAYS_INIT = ['2026-05-20'];
// Special workdays that override a weekly holiday (e.g. Wed that we open)
const SPECIAL_WORKDAYS_INIT = [];
// Day-level overrides keyed by date: { [date]: { early:[], mid:[], late:[] } }
const DAY_OVERRIDES_INIT = {
  // sample override so user sees the concept
  '2026-05-15': { early: ['d1','d3','d6'], mid: ['d2','d5'], late: ['d4','d7'] },
};

// Pattern types
const PATTERN_TYPES = [
  { id: 'weekly',             label: '每週重複',     hint: '以週為單位，週一~週日個別設定' },
  { id: 'biweekly',           label: '雙週循環',     hint: 'A週 / B週 交替，常見於双醫師輪班' },
  { id: 'n_day_cycle',        label: '每 N 天循環', hint: '例如 3 天一循環、不跟週幾走' },
  { id: 'monthly_by_date',    label: '每月固定日期', hint: '例如每月 1 / 15 / 28 號安排特定醫師' },
  { id: 'monthly_by_weekday', label: '每月第 N 個星期', hint: '例如每月第 2 個星期一 (尚未開放)', wip: true },
  { id: 'custom_range',       label: '自訂日期區間', hint: '代班 / 特例事件 (尚未開放)', wip: true },
];

const N_CYCLE_INIT = {
  length: 3, anchor: '2026-05-04',
  items: {
    0: { early: ['d1','d2'], mid: ['d3'],      late: ['d4'] },
    1: { early: ['d3','d5'], mid: ['d6'],      late: ['d1'] },
    2: { early: [],          mid: [],          late: []      }, // 休
  },
};
const BIWEEKLY_INIT = {
  anchor: '2026-05-04', // Monday of week A
  items: {
    // 0..6 = A週（6..12 = B週
    0: { early:['d1'], mid:['d2'], late:['d3'] }, 1: { early:['d4'], mid:['d5'], late:['d6'] },
    2: { early:[],     mid:[],     late:[]     }, 3: { early:['d1'], mid:['d2'], late:['d3'] },
    4: { early:['d4'], mid:['d5'], late:['d6'] }, 5: { early:['d7'], mid:['d1','d2'], late:['d3'] },
    6: { early:['d4','d5'], mid:['d6'], late:['d7'] },
    7: { early:['d4'], mid:['d5'], late:['d6'] }, 8: { early:['d7'], mid:['d1'], late:['d2'] },
    9: { early:[],     mid:[],     late:[]     }, 10:{ early:['d3'], mid:['d4'], late:['d5'] },
    11:{ early:['d6'], mid:['d7'], late:['d1'] }, 12:{ early:['d2','d3'], mid:['d4'], late:['d5'] },
    13:{ early:['d6','d7'], mid:['d1'], late:['d2'] },
  },
};
const MONTHLY_DATE_INIT = {
  // Sparse: only days that have explicit assignments
  items: {
    1:  { early: ['d1'], mid: ['d2'], late: ['d3'] },
    15: { early: ['d4'], mid: ['d5'], late: ['d6'] },
    28: { early: ['d7'], mid: ['d1'], late: ['d2'] },
  },
};

// Per-month status: { [yyyy-mm]: { status, publishedAt, publishedSnapshot } }
// publishedSnapshot stores the day-overrides AND week-template AND holidays as-of-publish
const MONTH_STATUS_INIT = {
  '2026-04': { status: 'published', publishedAt: '2026-03-28 14:22',
    snapshot: { dayOverrides: {}, weekTemplate: WEEK_TEMPLATE_INIT,
      weeklyHolidays: WEEKLY_HOLIDAYS_INIT, specialHolidays: [], specialWorkdays: [] } },
  '2026-05': { status: 'draft' },
};

// ── helpers ──────────────────────────────────────────────────────────────
const WEEKDAYS_ZH = ['一','二','三','四','五','六','日']; // Mon-first
const MONTHS_ZH = ['一','二','三','四','五','六','七','八','九','十','十一','十二'];

function fmtDate(y, m, d) {
  return `${y}-${String(m+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
}
function parseDate(s) {
  const [y,m,d] = s.split('-').map(Number); return new Date(y, m-1, d);
}
// Mon=0..Sun=6
function monIdx(date) { return (date.getDay() + 6) % 7; }

function getMonthGrid(year, monthIdx) {
  // Return 6×7 grid of { y,m,d, inMonth, weekday } starting Mon
  const first = new Date(year, monthIdx, 1);
  const firstW = monIdx(first); // offset
  const start = new Date(year, monthIdx, 1 - firstW);
  const cells = [];
  for (let i = 0; i < 42; i++) {
    const cur = new Date(start);
    cur.setDate(start.getDate() + i);
    cells.push({
      y: cur.getFullYear(),
      m: cur.getMonth(),
      d: cur.getDate(),
      inMonth: cur.getMonth() === monthIdx,
      weekday: monIdx(cur),
      iso: fmtDate(cur.getFullYear(), cur.getMonth(), cur.getDate()),
      jsDate: new Date(cur),
    });
  }
  return cells;
}

function isHolidayFor(iso, weekday, state) {
  const { weeklyHolidays, specialHolidays, specialWorkdays } = state;
  if (specialWorkdays.includes(iso)) return false;
  if (specialHolidays.includes(iso)) return true;
  return weeklyHolidays.includes(weekday);
}

function resolveShifts(iso, weekday, state) {
  // Returns { early:[ids], mid:[ids], late:[ids], overridden:bool, holiday:bool }
  const holiday = isHolidayFor(iso, weekday, state);
  if (holiday) return { early: [], mid: [], late: [], overridden: false, holiday: true };
  const ov = state.dayOverrides[iso];
  if (ov) return { ...ov, overridden: true, holiday: false };
  const tpl = patternShiftsFor(state, iso, weekday);
  return { ...tpl, overridden: false, holiday: false };
}

function docById(doctors, id) { return doctors.find(d => d.id === id); }

// Per-weekday shift time override. shift.dayTimes = { [weekday0..6]: { start, end } } (optional, sparse)
function shiftTimeFor(shift, weekday) {
  const ov = shift.dayTimes && shift.dayTimes[weekday];
  if (ov && ov.start && ov.end) return { start: ov.start, end: ov.end, custom: true };
  return { start: shift.start, end: shift.end, custom: false };
}

// Compose default app state.
function makeInitialState() {
  return {
    doctors: DOCTORS_INIT,
    shifts: SHIFTS_INIT,
    weeklyHolidays: WEEKLY_HOLIDAYS_INIT,
    specialHolidays: SPECIAL_HOLIDAYS_INIT,
    specialWorkdays: SPECIAL_WORKDAYS_INIT,
    holidayNotes: { '2026-05-20': '員工旅遊' },
    patternType: 'weekly',
    weekTemplate: WEEK_TEMPLATE_INIT,
    cycleConfig: N_CYCLE_INIT,
    biweeklyConfig: BIWEEKLY_INIT,
    monthlyDateConfig: MONTHLY_DATE_INIT,
    dayOverrides: DAY_OVERRIDES_INIT,
    monthStatus: MONTH_STATUS_INIT,
  };
}

function patternShiftsFor(state, iso, weekday) {
  const pt = state.patternType || 'weekly';
  const empty = { early: [], mid: [], late: [] };
  if (pt === 'weekly') return state.weekTemplate[weekday] || empty;
  if (pt === 'biweekly') {
    const anchor = parseDate(state.biweeklyConfig.anchor);
    const days = Math.floor((parseDate(iso) - anchor) / 86400000);
    const idx = ((days % 14) + 14) % 14;
    return state.biweeklyConfig.items[idx] || empty;
  }
  if (pt === 'n_day_cycle') {
    const anchor = parseDate(state.cycleConfig.anchor);
    const len = state.cycleConfig.length;
    const days = Math.floor((parseDate(iso) - anchor) / 86400000);
    const idx = ((days % len) + len) % len;
    return state.cycleConfig.items[idx] || empty;
  }
  if (pt === 'monthly_by_date') {
    const dom = parseDate(iso).getDate();
    return state.monthlyDateConfig.items[dom] || empty;
  }
  return empty;
}

function monthKey(y, m) { return `${y}-${String(m+1).padStart(2,'0')}`; }
function getMonthMeta(state, y, m) {
  return state.monthStatus[monthKey(y,m)] || { status: 'draft' };
}
// Get overrides for a month — published snapshot or live draft
function overridesForView(state, y, m, view) {
  // view: 'live' (always current state) | 'published' (use snapshot if exists)
  if (view === 'published') {
    const meta = getMonthMeta(state, y, m);
    if (meta.status === 'published' && meta.snapshot) {
      return meta.snapshot;
    }
    // No published version — fall back to nothing
    return null;
  }
  return null;
}

Object.assign(window, {
  DOCTORS_INIT, SHIFTS_INIT, WEEKLY_HOLIDAYS_INIT, PATTERN_TYPES,
  WEEK_TEMPLATE_INIT, SPECIAL_HOLIDAYS_INIT, SPECIAL_WORKDAYS_INIT,
  DAY_OVERRIDES_INIT, MONTH_STATUS_INIT, WEEKDAYS_ZH, MONTHS_ZH,
  fmtDate, parseDate, monIdx, getMonthGrid, monthKey, getMonthMeta, overridesForView,
  isHolidayFor, resolveShifts, patternShiftsFor, docById, makeInitialState,
  shiftTimeFor,
});
