// ov2-heatmap14-data.jsx — focused occupancy calendar mock for Overview v2

const HM14_CABINS = [
  { id: 'bali', name: 'Bali', sub: 'Garden view' },
  { id: 'cyprus', name: 'Cyprus', sub: 'Forest side' },
  { id: 'portofino', name: 'Portofino', sub: 'Quiet corner' },
  { id: 'latvia', name: 'Latvia', sub: 'Main lane' },
  { id: 'maldives', name: 'Maldives', sub: 'Premium' },
];

const HM14_START = new Date(2026, 4, 11);
HM14_START.setHours(0, 0, 0, 0);
const HM14_TODAY_IDX = 7;

const HM14_RES = [
  {
    id: 'HM-3101', cabin: 'bali', from: 5, to: 8, guest: 'Ivanova Marina', init: 'IM', flag: '🇱🇻', country: 'LV',
    seg: 'Returning', repeat: 2, channel: 'Phone', discovery: 'Google search', price: 190, total: 570,
    pay: 'unpaid', overdue: true, email: 'ivanova.marina@example.com', phone: '+371 26 110 240', lang: 'LV/RU',
    note: 'Просила поздний check-in и чай в домик.', spa: false, fnb: true,
    tasks: [
      { id: 't-3101-1', text: 'Запросить оплату до 18:00', prio: 'high', day: 7, done: false },
      { id: 't-3101-2', text: 'Проверить мини-бар', prio: 'med', day: 6, done: true },
    ],
  },
  {
    id: 'HM-3102', cabin: 'bali', from: 7, to: 10, guest: 'Иванов Александр', init: 'ИА', flag: '🇱🇻', country: 'LV',
    seg: 'VIP', repeat: 3, channel: 'Direct', discovery: 'Returning guest', price: 207, total: 621,
    pay: 'paid', email: 'ivanov.a@example.com', phone: '+371 27 114 689', lang: 'RU/LV',
    note: 'Просили поздний check-out. Предложить couple massage.', spa: true, fnb: true,
    tasks: [
      { id: 't-3102-1', text: 'Welcome wine в 16:00', prio: 'med', day: 7, done: false },
      { id: 't-3102-2', text: 'Предложить SPA upgrade', prio: 'low', day: 8, done: false },
    ],
  },
  {
    id: 'HM-3103', cabin: 'bali', from: 11, to: 14, guest: 'Anderson Mark', init: 'AM', flag: '🇺🇸', country: 'US',
    seg: 'Couple', repeat: 2, channel: 'Direct', discovery: 'Google Ads', price: 280, total: 840,
    pay: 'unpaid', overdue: true, email: 'mark.anderson@example.com', phone: '+371 29 450 772', lang: 'EN',
    note: 'Anniversary couple, send champagne.', spa: true, fnb: true,
    tasks: [{ id: 't-3103-1', text: 'Подтвердить anniversary setup', prio: 'high', day: 11, done: false }],
  },
  {
    id: 'HM-3104', cabin: 'bali', from: 16, to: 20, guest: 'Lehtonen Oskari', init: 'LO', flag: '🇫🇮', country: 'FI',
    seg: 'New guest', repeat: 1, channel: 'Booking.com', discovery: 'Booking.com', price: 235, total: 940,
    pay: 'paid', email: 'oskari.lehtonen@example.com', phone: '+371 25 801 441', lang: 'EN',
    note: null, spa: false, fnb: false,
    tasks: [],
  },
  {
    id: 'HM-3111', cabin: 'cyprus', from: 7, to: 9, guest: 'Raudsepp Liis', init: 'RL', flag: '🇪🇪', country: 'EE',
    seg: 'Family', repeat: 1, channel: 'Booking.com', discovery: 'Google search', price: 270, total: 540,
    pay: 'hold', email: 'liis.raudsepp@example.com', phone: '+371 26 530 120', lang: 'EN',
    note: 'Baby cot needed.', spa: false, fnb: true,
    tasks: [{ id: 't-3111-1', text: 'Поставить детскую кроватку', prio: 'high', day: 7, done: false }],
  },
  {
    id: 'HM-3112', cabin: 'cyprus', from: 11, to: 14, guest: 'Nowak Marta', init: 'NM', flag: '🇵🇱', country: 'PL',
    seg: 'New guest', repeat: 1, channel: 'Expedia', discovery: 'Expedia', price: 240, total: 720,
    pay: 'unpaid', overdue: true, email: 'marta.nowak@example.com', phone: '+371 22 330 019', lang: 'EN',
    note: null, spa: false, fnb: false,
    tasks: [{ id: 't-3112-1', text: 'Payment reminder', prio: 'high', day: 11, done: false }],
  },
  {
    id: 'HM-3113', cabin: 'cyprus', from: 16, to: 18, guest: 'Berzina Liene', init: 'BL', flag: '🇱🇻', country: 'LV',
    seg: 'Returning', repeat: 2, channel: 'WhatsApp', discovery: 'Instagram', price: 215, total: 430,
    pay: 'paid', email: 'liene.berzina@example.com', phone: '+371 24 910 111', lang: 'LV',
    note: null, spa: false, fnb: false,
    tasks: [],
  },
  {
    id: 'HM-3121', cabin: 'portofino', from: 3, to: 6, guest: 'Kask Anna', init: 'KA', flag: '🇪🇪', country: 'EE',
    seg: 'Returning', repeat: 3, channel: 'WhatsApp', discovery: 'Word of mouth', price: 230, total: 690,
    pay: 'partial', email: 'anna.kask@example.com', phone: '+371 25 779 204', lang: 'EN',
    note: 'Anniversary couple, send champagne.', spa: true, fnb: true,
    tasks: [],
  },
  {
    id: 'HM-3122', cabin: 'portofino', from: 12, to: 14, guest: 'Vasiljev Dmitri', init: 'VD', flag: '🇪🇪', country: 'EE',
    seg: 'Family', repeat: 1, channel: 'WhatsApp', discovery: 'Instagram', price: 260, total: 520,
    pay: 'unpaid', overdue: true, email: 'dmitri.vasiljev@example.com', phone: '+371 20 487 300', lang: 'RU/EN',
    note: 'SPA package requested.', spa: true, fnb: false,
    tasks: [{ id: 't-3122-1', text: 'Подтвердить SPA package', prio: 'high', day: 12, done: false }],
  },
  {
    id: 'HM-3123', cabin: 'portofino', from: 18, to: 20, guest: 'Petrov Kirill', init: 'PK', flag: '🇷🇺', country: 'RU',
    seg: 'New guest', repeat: 1, channel: 'Phone', discovery: 'Google search', price: 210, total: 420,
    pay: 'paid', email: 'kirill.petrov@example.com', phone: '+371 21 448 820', lang: 'RU',
    note: 'Confirmation call needed.', spa: false, fnb: false,
    tasks: [{ id: 't-3123-1', text: 'Контрольный звонок', prio: 'med', day: 18, done: false }],
  },
  {
    id: 'HM-3124', cabin: 'portofino', from: 9, to: 11, blocked: true, reason: 'Maintenance deep clean',
    guest: 'Maintenance', init: 'БЛОК', flag: '', country: '', seg: 'Blocked', repeat: 0, channel: '-', discovery: '-',
    price: 0, total: 0, pay: 'hold', email: '', phone: '', lang: '-', note: 'Deep cleaning and minor repair.', spa: false, fnb: false, tasks: [],
  },
  {
    id: 'HM-3131', cabin: 'latvia', from: 6, to: 9, guest: 'Kalnina Elina', init: 'KE', flag: '🇱🇻', country: 'LV',
    seg: 'New guest', repeat: 1, channel: 'Instagram DM', discovery: 'Instagram', price: 230, total: 690,
    pay: 'paid', email: 'elina.kalnina@example.com', phone: '+371 20 601 311', lang: 'LV',
    note: 'Prefers quiet cabin.', spa: true, fnb: false,
    tasks: [],
  },
  {
    id: 'HM-3132', cabin: 'latvia', from: 10, to: 12, guest: 'Orlova Marina', init: 'OM', flag: '🇱🇻', country: 'LV',
    seg: 'Couple', repeat: 1, channel: 'Direct', discovery: 'Word of mouth', price: 245, total: 490,
    pay: 'hold', email: 'marina.orlova@example.com', phone: '+371 28 030 622', lang: 'RU/LV',
    note: 'Welcome wine.', spa: false, fnb: true,
    tasks: [{ id: 't-3132-1', text: 'Welcome wine', prio: 'med', day: 10, done: false }],
  },
  {
    id: 'HM-3133', cabin: 'latvia', from: 15, to: 18, guest: 'Virtanen Aino', init: 'VA', flag: '🇫🇮', country: 'FI',
    seg: 'Family', repeat: 1, channel: 'Booking.com', discovery: 'Booking.com', price: 295, total: 885,
    pay: 'partial', email: 'aino.virtanen@example.com', phone: '+371 23 220 842', lang: 'EN',
    note: null, spa: false, fnb: false,
    tasks: [],
  },
  {
    id: 'HM-3141', cabin: 'maldives', from: 5, to: 8, guest: 'Laine Sofia', init: 'LS', flag: '🇫🇮', country: 'FI',
    seg: 'VIP', repeat: 4, channel: 'WhatsApp', discovery: 'Returning guest', price: 235, total: 705,
    pay: 'unpaid', overdue: true, email: 'sofia.laine@example.com', phone: '+371 29 600 312', lang: 'EN',
    note: 'Allergy: nuts in SPA.', spa: true, fnb: true,
    tasks: [{ id: 't-3141-1', text: 'Аллергия: предупредить SPA', prio: 'high', day: 7, done: false }],
  },
  {
    id: 'HM-3142', cabin: 'maldives', from: 7, to: 10, guest: 'Virtanen Aino', init: 'VA', flag: '🇫🇮', country: 'FI',
    seg: 'Family', repeat: 1, channel: 'Booking.com', discovery: 'Booking.com', price: 295, total: 885,
    pay: 'paid', email: 'aino.virtanen@example.com', phone: '+371 23 220 842', lang: 'EN',
    note: null, spa: false, fnb: false,
    tasks: [],
  },
  {
    id: 'HM-3143', cabin: 'maldives', from: 12, to: 15, guest: 'Tamm Kristjan', init: 'TK', flag: '🇪🇪', country: 'EE',
    seg: 'Family', repeat: 1, channel: 'Instagram DM', discovery: 'Meta Ads', price: 305, total: 915,
    pay: 'paid', email: 'kristjan.tamm@example.com', phone: '+371 22 302 778', lang: 'EN',
    note: null, spa: true, fnb: false,
    tasks: [],
  },
  {
    id: 'HM-3144', cabin: 'maldives', from: 18, to: 22, guest: 'Hoffmann Dieter', init: 'HD', flag: '🇩🇪', country: 'DE',
    seg: 'VIP', repeat: 5, channel: 'Direct', discovery: 'Returning guest', price: 300, total: 1200,
    pay: 'hold', email: 'dieter.hoffmann@example.com', phone: '+371 24 889 101', lang: 'EN/DE',
    note: 'Same wine as last stay.', spa: true, fnb: true,
    tasks: [{ id: 't-3144-1', text: 'Repeat preference: wine', prio: 'low', day: 18, done: false }],
  },
];

const HM14_STANDALONE_TASKS = [
  { id: 'st-1', text: 'Проверить свободные окна weekend', prio: 'med', day: 11, done: false, scope: 'global' },
  { id: 'st-2', text: 'Фото для Instagram stories', prio: 'low', day: 8, done: false, cabin: 'bali' },
  { id: 'st-3', text: 'Last-minute оффер', prio: 'high', day: 9, done: false, cabin: 'portofino' },
  { id: 'st-4', text: 'Проверить оплату до заезда', prio: 'high', day: 12, done: false, scope: 'global' },
  { id: 'st-5', text: 'SPA cross-sell гостям без записи', prio: 'med', day: 15, done: false, scope: 'global' },
];

const HM14_DOW = {
  ru: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
  en: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
};
const HM14_MONTHS = {
  ru: ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'],
  en: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
};

const HM14_addDays = (idx) => {
  const d = new Date(HM14_START);
  d.setDate(d.getDate() + idx);
  return d;
};

const HM14_fmtFullDate = (idx, lang = 'ru') => {
  const d = HM14_addDays(idx);
  const dow = HM14_DOW[lang] || HM14_DOW.ru;
  const months = HM14_MONTHS[lang] || HM14_MONTHS.ru;
  return `${dow[d.getDay()]}, ${d.getDate()} ${months[d.getMonth()]} 2026`;
};

const HM14_buildDays = (offset, count) => Array.from({ length: count }, (_, i) => {
  const idx = offset + i;
  const d = HM14_addDays(idx);
  return {
    idx,
    date: d,
    dow: d.getDay(),
    day: d.getDate(),
    month: d.getMonth(),
    isToday: idx === HM14_TODAY_IDX,
    isWeekend: d.getDay() === 0 || d.getDay() === 6,
  };
});

const HM14_resFor = (cabinId, dayIdx) => HM14_RES.find((res) => res.cabin === cabinId && dayIdx >= res.from && dayIdx < res.to);

const HM14_dayCellModel = (cabinId, dayIdx) => {
  const res = HM14_resFor(cabinId, dayIdx);
  if (!res) return { type: 'free', res: null, isArrival: false, isDeparture: false };
  const isArrival = dayIdx === res.from;
  const isDeparture = dayIdx === res.to - 1;
  if (res.blocked) return { type: 'blocked', res, isArrival, isDeparture };
  const coversToday = HM14_TODAY_IDX >= res.from && HM14_TODAY_IDX < res.to;
  const type = coversToday ? 'inhouse' : res.to <= HM14_TODAY_IDX ? 'checkedout' : 'booked';
  return { type, res, isArrival, isDeparture };
};

const HM14_tasksFor = (cabinId, dayIdx, res) => {
  const bookingTasks = (res && res.tasks ? res.tasks : []).filter((task) => task.day === dayIdx).map((task) => ({ ...task, source: 'booking' }));
  const standalone = HM14_STANDALONE_TASKS.filter((task) => (
    task.day === dayIdx && (task.scope === 'global' || task.cabin === cabinId)
  )).map((task) => ({ ...task, source: 'standalone' }));
  return bookingTasks.concat(standalone);
};

const HM14_I18N = {
  ru: {
    title: 'Загрузка · ближайшие {n} дней',
    help: 'Матрица домиков и дней: статус проживания, оплаты, задач и источника клиента. Клик открывает детальную карточку дня.',
    prev: 'Назад',
    next: 'Вперед',
    today: 'Сегодня',
    range: '{from} — {to}',
    toggles: { 7: '7 дней', 14: '14 дней', 30: '30 дней' },
    stats: { occupied: 'занято', free: 'свободно', overdue: 'просрочено оплат', tasks: 'активных задач' },
    legend: { inhouse: 'in-house', booked: 'бронь', free: 'свободно', arrdep: 'заезд/выезд', pay: 'оплата', overdue: 'overdue' },
    payment: { paid: 'оплачено', partial: 'частично', unpaid: 'не оплачено', hold: 'hold' },
    type: { free: 'Свободно', blocked: 'Блок', inhouse: 'In-house', booked: 'Бронь', checkedout: 'Выезд завершен' },
    marker: { arrival: 'заезд', departure: 'выезд' },
    drawer: {
      booking: 'Бронь',
      free: 'Свободно',
      blocked: 'Блок',
      price: 'Цена/ночь',
      total: 'Итого',
      payment: 'Оплата',
      operations: 'Operations',
      tasks: 'Задачи на день',
      client: 'Клиент',
      source: 'Источник',
      bookingSec: 'Бронь',
      note: 'Reception note',
      noTasks: 'Нет задач на этот день',
      openCloudbeds: 'Открыть в Cloudbeds',
      whatsapp: 'WhatsApp',
      requestPayment: 'Запросить оплату',
      freeHint: 'Свободное окно: можно запустить last-minute оффер или SPA+ночь пакет.',
      blockedHint: 'День заблокирован: проверьте причину и можно ли вернуть его в продажу.',
      opArrival: 'День заезда: готовность домика, welcome-сообщение, оплата до прибытия.',
      opDeparture: 'День выезда: запросить отзыв, обновить CRM-профиль и заметки.',
      opInhouse: 'Гость проживает сегодня: проверить заметки, SPA/F&B upsell и качество сервиса.',
      opFuture: 'Будущая бронь: проверить оплату, источник и pre-arrival коммуникацию.',
      opPast: 'Прошедшая ночь: использовать данные для CRM-сегментации и repeat-маркетинга.',
    },
    labels: {
      guest: 'Гость', country: 'Страна', segment: 'Сегмент', repeat: 'Повторы', contacts: 'Контакты',
      channel: 'Канал', discovery: 'Discovery', id: 'ID', checkin: 'Check-in', checkout: 'Check-out', reason: 'Причина',
    },
  },
  en: {
    title: 'Occupancy · next {n} days',
    help: 'Cabin/day matrix with stay status, payment, tasks, and customer source. Click opens day detail.',
    prev: 'Back',
    next: 'Forward',
    today: 'Today',
    range: '{from} — {to}',
    toggles: { 7: '7 days', 14: '14 days', 30: '30 days' },
    stats: { occupied: 'occupied', free: 'free', overdue: 'overdue payments', tasks: 'active tasks' },
    legend: { inhouse: 'in-house', booked: 'booked', free: 'free', arrdep: 'arrival/departure', pay: 'payment', overdue: 'overdue' },
    payment: { paid: 'paid', partial: 'partial', unpaid: 'unpaid', hold: 'hold' },
    type: { free: 'Free', blocked: 'Blocked', inhouse: 'In-house', booked: 'Booked', checkedout: 'Checked out' },
    marker: { arrival: 'arrival', departure: 'departure' },
    drawer: {
      booking: 'Booking',
      free: 'Free',
      blocked: 'Blocked',
      price: 'Night rate',
      total: 'Total',
      payment: 'Payment',
      operations: 'Operations',
      tasks: 'Tasks for this day',
      client: 'Client',
      source: 'Source',
      bookingSec: 'Booking',
      note: 'Reception note',
      noTasks: 'No tasks for this day',
      openCloudbeds: 'Open in Cloudbeds',
      whatsapp: 'WhatsApp',
      requestPayment: 'Request payment',
      freeHint: 'Open night: push a last-minute offer or SPA+stay package.',
      blockedHint: 'Blocked day: check the reason and whether it can return to sale.',
      opArrival: 'Arrival day: cabin readiness, welcome message, payment before arrival.',
      opDeparture: 'Departure day: request review, update CRM profile and notes.',
      opInhouse: 'Guest is in-house today: check notes, SPA/F&B upsell, and service quality.',
      opFuture: 'Future booking: check payment, source, and pre-arrival communication.',
      opPast: 'Past night: use data for CRM segmentation and repeat marketing.',
    },
    labels: {
      guest: 'Guest', country: 'Country', segment: 'Segment', repeat: 'Repeat', contacts: 'Contacts',
      channel: 'Channel', discovery: 'Discovery', id: 'ID', checkin: 'Check-in', checkout: 'Check-out', reason: 'Reason',
    },
  },
};

window.HM14 = {
  CABINS: HM14_CABINS,
  RES: HM14_RES,
  STANDALONE_TASKS: HM14_STANDALONE_TASKS,
  START: HM14_START,
  TODAY_IDX: HM14_TODAY_IDX,
  buildDays: HM14_buildDays,
  dayCellModel: HM14_dayCellModel,
  tasksFor: HM14_tasksFor,
  DOW: HM14_DOW,
  MONTHS: HM14_MONTHS,
  fmtFullDate: HM14_fmtFullDate,
};
window.HM14_I18N = HM14_I18N;
