/* global window */
// Schools.ArtemenkoCRM — mock data (real model: Клиенты + Заявки)
// Contacts model: student & each parent has contacts: [{ type, value }] (max 4).

const TEACHERS = ['Гневанова Анна Алексеевна', 'Гончаренко Виталий Вадимович'];
const DIRECTIONS = ['Python', 'C++', 'Вышмат', 'Другое'];
const SOURCES = ['Сайт', 'Рекомендация', 'Профи.ру', 'Другое'];

// Каналы связи — порядок как в продукте.
// mask: формат ввода значения; ph: подсказка-плейсхолдер под выбранный канал.
//   phone  — телефонная маска +7 (___) ___-__-__ (моноширинно): Телефон, Вайбер, Ватсапп, Макс
//   handle — @никнейм (Телеграм)
//   vk     — vk.com/никнейм
//   null   — свободный ввод
const CONTACT_TYPES = [
  { value: 'max',      label: 'Макс',     icon: 'message-square', mono: true,  mask: 'phone',  ph: '+7 (___) ___-__-__' },
  { value: 'telegram', label: 'Телеграм', icon: 'send',           mono: false, mask: 'handle', ph: '@username' },
  { value: 'phone',    label: 'Телефон',  icon: 'phone',          mono: true,  mask: 'phone',  ph: '+7 (___) ___-__-__' },
  { value: 'vk',       label: 'ВК',       icon: 'message-circle', mono: false, mask: 'vk',     ph: 'vk.com/username' },
  { value: 'viber',    label: 'Вайбер',   icon: 'phone-call',     mono: true,  mask: 'phone',  ph: '+7 (___) ___-__-__' },
  { value: 'whatsapp', label: 'Ватсапп',  icon: 'message-circle', mono: true,  mask: 'phone',  ph: '+7 (___) ___-__-__' },
  { value: 'other',    label: 'Другое',   icon: 'at-sign',        mono: false, mask: null,     ph: '@username или номер' },
];

// Привести значение контакта к маске выбранного канала (вызывается при наборе текста).
function maskContactValue(type, raw) {
  const t = CONTACT_TYPES.find(x => x.value === type) || {};
  const v = raw == null ? '' : String(raw);
  if (t.mask === 'phone') return window.formatPhone ? window.formatPhone(v) : v;
  if (t.mask === 'handle') { const h = v.replace(/^@+/, '').replace(/[^\w.]/g, ''); return h ? '@' + h : ''; }
  if (t.mask === 'vk') { const id = v.trim().replace(/^https?:\/\//i, '').replace(/^vk\.com\//i, '').replace(/^@+/, '').replace(/[^\w.]/g, ''); return id ? 'vk.com/' + id : ''; }
  return v;
}
window.maskContactValue = maskContactValue;

// При СМЕНЕ канала перестроить поле под новую маску.
// Между телефонными каналами (Телефон/Вайбер/Ватсапп/Макс) номер сохраняется;
// при переходе в другое семейство поле очищается под новый формат (плейсхолдер подскажет).
function reseedContactValue(newType, oldType, oldValue) {
  const nt = CONTACT_TYPES.find(x => x.value === newType) || {};
  const ot = CONTACT_TYPES.find(x => x.value === oldType) || {};
  if (nt.mask === 'phone') return ot.mask === 'phone' ? maskContactValue(newType, oldValue) : '+7 ';
  return '';
}
window.reseedContactValue = reseedContactValue;

// ---- Ставка преподавателя во времени ----
// rateHistory: [{ from: 'YYYY-MM-DD', rate }] — ставка действует с указанной даты.
// Менять ставку задним числом можно, но это пересчитывает только НЕ проведённые выплаты.
const APP_TODAY_ISO = '2026-05-31';
window.APP_TODAY_ISO = APP_TODAY_ISO;
const _RATE_ABBR = ['янв', 'фев', 'мар', 'апр', 'мая', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'];
// Ставка, действующая на дату dateISO (по истории ставок сотрудника).
function rateOn(staffOrHist, dateISO) {
  const hist = Array.isArray(staffOrHist)
    ? staffOrHist
    : ((staffOrHist.rateHistory && staffOrHist.rateHistory.length) ? staffOrHist.rateHistory : null);
  if (!hist || !hist.length) return Array.isArray(staffOrHist) ? 0 : (staffOrHist.rate || 0);
  const sorted = hist.slice().sort((a, b) => (a.from < b.from ? -1 : 1));
  let r = sorted[0].rate;
  for (let i = 0; i < sorted.length; i++) { if (sorted[i].from <= dateISO) r = sorted[i].rate; else break; }
  return r;
}
window.rateOn = rateOn;
// Дата найма сотрудника в ISO (для опции «за весь период работы»).
function staffHireISO(staff) {
  const m = String((staff && staff.since) || '').toLowerCase().match(/(\d{1,2})\s+([а-я]+)\s+(\d{4})/);
  if (!m) return '2000-01-01';
  const mi = _RATE_ABBR.findIndex(x => m[2].startsWith(x));
  return `${m[3]}-${String((mi < 0 ? 0 : mi) + 1).padStart(2, '0')}-${String(+m[1]).padStart(2, '0')}`;
}
window.staffHireISO = staffHireISO;

const CLIENTS = [
  { id: 1,  child: 'Савелий',   self: false, animal: 'rabbit',    tone: 'navy',  contacts: [{ type: 'telegram', value: '@PeepoFS' }], parents: [{ name: 'Лариса', contacts: [{ type: 'phone', value: '+7 963 787-97-87' }] }], status: 'refusal', teacher: 'Гневанова Анна Алексеевна', balance: 0, direction: 'Вышмат', source: 'Рекомендация', manager: null, date: '16 апр, 23:06', refuseReason: 'Преподаватель', archived: false, lastLesson: '2026-04-16', lessonsMonth: 0, pastTeachers: ['Гончаренко Виталий Вадимович'] },
  { id: 2,  child: 'Клиент 6',  self: false, animal: 'cat',       tone: 'gold',  contacts: [], parents: [], status: 'new', teacher: null, balance: 0, direction: null, source: 'Сайт', manager: null, date: '18 апр, 22:23', refuseReason: null, archived: false },
  { id: 3,  child: 'Данияр Фаязович', self: false, animal: 'dog', tone: 'green', contacts: [], parents: [{ name: 'Фаяз', contacts: [{ type: 'phone', value: '+7 905 100-20-30' }] }], status: 'active', teacher: 'Гончаренко Виталий Вадимович', balance: 0, teacherPay: 700, direction: 'Python', source: 'Другое', manager: null, date: '5 апр, 23:08', refuseReason: null, archived: false, lastLesson: '2026-05-28', lessonsMonth: 5 },
  { id: 4,  child: 'София',     self: false, animal: 'butterfly', tone: 'gold',  contacts: [], parents: [{ name: 'Мадина', contacts: [{ type: 'phone', value: '+7 916 222-11-44' }, { type: 'telegram', value: '@madina_s' }] }], status: 'active', teacher: 'Гончаренко Виталий Вадимович', balance: 0, teacherPay: 700, direction: 'Python', source: 'Другое', manager: null, date: '5 апр, 23:01', refuseReason: null, archived: false, lastLesson: '2026-05-30', lessonsMonth: 8 },
  { id: 5,  child: 'Артём',     self: false, animal: 'fish',      tone: 'navy',  contacts: [], parents: [{ name: 'Екатерина', contacts: [{ type: 'phone', value: '+7 903 555-66-77' }] }, { name: 'Сергей', contacts: [{ type: 'phone', value: '+7 903 555-10-20' }] }], status: 'active', teacher: 'Гончаренко Виталий Вадимович', balance: 16000, teacherPay: 800, direction: 'Python', source: 'Другое', manager: null, date: '5 апр, 23:19', refuseReason: null, archived: false, lastLesson: '2026-05-29', lessonsMonth: 9 },
  { id: 6,  child: 'Матвей',    self: false, animal: 'horse',     tone: 'green', contacts: [], parents: [{ name: 'Павел', contacts: [{ type: 'phone', value: '+7 925 808-09-10' }] }], status: 'active', teacher: 'Гончаренко Виталий Вадимович', balance: -3600, teacherPay: 700, direction: 'Python', source: 'Другое', manager: null, date: '5 апр, 23:02', refuseReason: null, archived: false, lastLesson: '2026-04-12', lessonsMonth: 0 },
  { id: 7,  child: 'Егор',      self: false, animal: 'bird',      tone: 'navy',  contacts: [], parents: [{ name: 'Елена', contacts: [{ type: 'phone', value: '+7 999 111-22-33' }] }], status: 'active', teacher: 'Гончаренко Виталий Вадимович', balance: -1800, direction: 'Python', source: 'Другое', manager: null, date: '5 апр, 23:06', refuseReason: null, archived: false, lastLesson: '2026-05-22', lessonsMonth: 4 },
  { id: 8,  child: 'Клиент 5',  self: false, animal: 'paw-print', tone: 'gold',  contacts: [], parents: [], status: 'call', teacher: null, balance: 0, direction: 'C++', source: 'Сайт', manager: null, date: '7 апр, 14:34', refuseReason: null, archived: false, lastLesson: '2026-02-10', pastTeachers: ['Гончаренко Виталий Вадимович'] },
  { id: 9,  child: 'Клиент 4',  self: false, animal: 'cat',       tone: 'navy',  contacts: [], parents: [], status: 'trial', teacher: null, balance: 0, direction: 'Python', source: 'Сайт', manager: null, date: '7 апр, 14:29', refuseReason: null, archived: false },
  { id: 10, child: 'Клиент 3',  self: false, animal: 'rabbit',    tone: 'green', contacts: [], parents: [], status: 'payment', teacher: 'Гневанова Анна Алексеевна', balance: 0, direction: 'C++', source: 'Сайт', manager: '@undefined', date: '7 апр, 14:21', refuseReason: null, archived: false, lastLesson: '2026-03-20', pastTeachers: ['Гончаренко Виталий Вадимович'] },
  { id: 11, child: 'Клиент 2',  self: false, animal: 'dog',       tone: 'gold',  contacts: [], parents: [{ name: 'Мама клиента 2', contacts: [] }], status: 'new', teacher: 'Гневанова Анна Алексеевна', balance: 10, direction: 'Другое', source: 'Сайт', manager: '@undefined', date: '7 апр, 13:47', refuseReason: null, archived: false },
  { id: 12, child: 'Клиент 1',  self: false, animal: 'fish',      tone: 'navy',  contacts: [], parents: [], status: 'new', teacher: 'Гневанова Анна Алексеевна', balance: 0, direction: null, source: 'Сайт', manager: '@maximkuznetsov20', date: '6 апр, 18:24', refuseReason: null, archived: false, lastLesson: '2026-01-15', pastTeachers: ['Гончаренко Виталий Вадимович'] },
  { id: 13, child: 'Иван',      self: true,  animal: 'horse',     tone: 'green', contacts: [{ type: 'telegram', value: '@ivan_codes' }, { type: 'phone', value: '+7 911 200-30-40' }], parents: [], status: 'active', teacher: 'Гончаренко Виталий Вадимович', balance: 0, direction: 'Python', source: 'Профи.ру', manager: null, date: '5 апр, 23:17', refuseReason: null, archived: false, lastLesson: '2026-05-27', lessonsMonth: 7 },
  { id: 14, child: 'Лукас',     self: true,  animal: 'butterfly', tone: 'navy',  contacts: [{ type: 'phone', value: '+7 911 400-50-60' }], parents: [], status: 'active', teacher: 'Гончаренко Виталий Вадимович', balance: 0, direction: 'Python', source: 'Профи.ру', manager: null, date: '5 апр, 23:10', refuseReason: null, archived: false, lastLesson: '2026-04-15', lessonsMonth: 1 },
  { id: 15, child: 'Дарья',     self: false, animal: 'butterfly', tone: 'gold',  contacts: [], parents: [{ name: 'Ольга', contacts: [{ type: 'phone', value: '+7 906 333-22-11' }] }], status: 'refusal', teacher: null, balance: 0, direction: 'Python', source: 'Сайт', manager: null, date: '2 фев, 19:40', refuseReason: 'Сменили преподавателя', archived: true, lastLesson: '2025-12-20', lessonsMonth: 0, pastTeachers: ['Гончаренко Виталий Вадимович'] },
];

// Менеджеры подтягиваются из сотрудников с ролью «менеджер» (а не хардкод-список).
// В списке — ФИО (как у преподавателей): бэк резолвит менеджера и по full_name, а заявки/клиенты
// хранят и показывают менеджера именно по ФИО (listLeads → st.full_name). Раньше показывался tg/login.
function deriveManagers() {
  return (typeof STAFF !== 'undefined' ? STAFF : []).filter(s => s.role === 'manager' && s.status !== 'fired').map(s => s.name);
}
// Преподаватели — из сотрудников с ролью «преподаватель» (живой список, не хардкод).
function deriveTeachers() {
  return (typeof STAFF !== 'undefined' ? STAFF : []).filter(s => s.role === 'teacher' && s.status !== 'fired').map(s => s.name);
}

// ---- Расписание ----
// Read-only mirror of teacher schedules (the teacher product feeds this via integration).
// Event status: planned | paid | noshow | cancelled. day = 0..6 (Пн..Вс), times in hours.
const LESSON_STATUS = {
  planned:   { label: 'Запланировано', bd: '#6d52ff', bg: 'rgba(109,82,255,0.14)', fg: '#3a2a99', dot: '#6d52ff' },
  paid:      { label: 'Оплачено',      bd: '#00b48f', bg: 'rgba(0,180,143,0.16)',  fg: '#047358', dot: '#00b48f' },
  debt:      { label: 'В долг',         bd: '#ec5b2a', bg: 'rgba(236,91,42,0.16)',  fg: '#9b3717', dot: '#ec5b2a' },
  noshow:    { label: 'Не пришёл',     bd: '#ec9b2a', bg: 'rgba(236,155,42,0.18)', fg: '#8a5408', dot: '#ec9b2a' },
  cancelled: { label: 'Отменено',      bd: '#ef4467', bg: 'rgba(239,68,103,0.14)', fg: '#9b1737', dot: '#ef4467' },
};
const SCHEDULE = {
  1: [
    // Понедельник
    { day: 0, start: 16, end: 17, who: 'Артём', status: 'paid' },
    { day: 0, start: 17, end: 18, who: 'София', status: 'paid' },
    { day: 0, start: 19, end: 20, who: 'Иван', status: 'paid' },
    // Вторник
    { day: 1, start: 16, end: 17, who: 'Данияр Фаязович', status: 'paid' },
    { day: 1, start: 18, end: 19, who: 'Артём', status: 'paid' },
    { day: 1, start: 19, end: 20, who: 'Егор', status: 'noshow' },
    // Среда
    { day: 2, start: 16, end: 17, who: 'София', status: 'paid' },
    { day: 2, start: 17, end: 18, who: 'Иван', status: 'paid' },
    // Четверг
    { day: 3, start: 16, end: 17, who: 'Артём', status: 'paid' },
    { day: 3, start: 18, end: 19, who: 'Данияр Фаязович', status: 'paid' },
    { day: 3, start: 20, end: 21, who: 'Матвей', status: 'cancelled' },
    // Пятница
    { day: 4, start: 16, end: 17, who: 'София', status: 'paid' },
    { day: 4, start: 17, end: 18, who: 'Лукас', status: 'noshow' },
    // Суббота
    { day: 5, start: 11, end: 12, who: 'Иван', status: 'paid' },
    { day: 5, start: 12, end: 13, who: 'Егор', status: 'paid' },
  ],
  2: [
    { day: 0, start: 10, end: 11, who: 'Алина Соколова', status: 'paid' },
    { day: 1, start: 14, end: 15, who: 'Пётр Васин', status: 'planned' },
    { day: 1, start: 15, end: 16, who: 'Группа ВМ-1', status: 'paid', group: true },
    { day: 3, start: 11, end: 12, who: 'Дарья Котова', status: 'noshow' },
    { day: 4, start: 18, end: 19, who: 'Олег Пнин', status: 'planned' },
    { day: 5, start: 12, end: 13.5, who: 'Группа C++ старт', status: 'paid', group: true },
  ],
};

// ---- Сотрудники ----
// role: teacher | manager | admin ; status: active | vacation | fired
const STAFF = [
  { id: 1, name: 'Гончаренко Виталий Вадимович', role: 'teacher', position: 'Старший преподаватель', animal: 'horse', tone: 'navy',  subjects: ['Python', 'C++'], rate: 900, contact: '+7 903 240-11-22', tg: '@goncharenko_v', status: 'active', since: '12 янв 2025', login: 'goncharenko', password: 'Vita2025!' },
  { id: 2, name: 'Гневанова Анна Алексеевна', role: 'teacher', position: 'Преподаватель', animal: 'cat', tone: 'gold', subjects: ['Вышмат', 'C++'], rate: 900, contact: '+7 916 555-77-10', tg: '@gnevanova', status: 'active', since: '03 фев 2025', login: 'gnevanova', password: 'Anna#7710' },
  { id: 3, name: 'Кузнецов Максим', role: 'manager', position: 'Продажи', animal: 'dog', tone: 'green', subjects: [], rate: 0, contact: '+7 925 100-20-30', tg: '@maximkuznetsov20', status: 'active', since: '20 дек 2024', login: 'm.kuznetsov', password: 'Sales2024' },
  { id: 4, name: 'Павел Программист', role: 'manager', position: 'Переписки', animal: 'rabbit', tone: 'navy', subjects: [], rate: 0, contact: '+7 999 240-50-60', tg: '@pavelproga', status: 'active', since: '05 фев 2025', login: 'pavel', password: 'Pavel!240' },
  { id: 5, name: 'Артём Админов', role: 'admin', position: 'Руководитель', animal: 'fish', tone: 'gold', subjects: [], rate: 0, contact: '+7 903 777-88-99', tg: '@admin', status: 'active', since: '01 дек 2024', login: 'admin', password: 'Root#0001' },
];

// ---- Финансы ----
const INVOICE_TYPES = [
  { value: 'month',  label: 'За месяц (×8 занятий)', mult: 8 },
  { value: 'month4', label: 'За месяц (×4 занятия)', mult: 4 },
  { value: 'lesson', label: 'За одно занятие', mult: 1 },
  { value: 'pack',   label: 'Пакет занятий', mult: 0 },
  { value: 'custom', label: 'Произвольная сумма', mult: 0 },
];
const INVOICE_TYPE_SHORT = { month: 'Месяц ×8', month4: 'Месяц ×4', lesson: 'Занятие', pack: 'Пакет', custom: 'Произв.' };
const PAYMENT_METHODS = ['СБП', 'Карта', 'Наличные', 'Перевод'];
const EXPENSE_CATEGORIES = ['Аренда', 'Реклама', 'Сервисы', 'Оборудование', 'Прочее'];

// status: paid | pending | overdue | cancelled | refund
const INVOICES = [
  { id: 46, clientId: 5,  parent: 'Екатерина', student: 'Артём',  type: 'month',  amount: 16000, method: 'СБП',   status: 'paid',    date: '27 мая, 13:43', due: '01 мая', desc: 'Оплата за май, Python' },
  { id: 45, clientId: 5,  parent: 'Екатерина', student: 'Артём',  type: 'month',  amount: 16000, method: 'Карта', status: 'paid',    date: '22 мая, 23:36', due: '01 мая', desc: '' },
  { id: 44, clientId: 6,  parent: 'Павел',     student: 'Матвей', type: 'lesson', amount: 1800,  method: 'СБП',   status: 'paid',    date: '16 мая, 10:09', due: '16 мая', desc: '' },
  { id: 43, clientId: 7,  parent: 'Елена',     student: 'Егор',   type: 'lesson', amount: 1800,  method: null,    status: 'cancelled', date: '16 мая, 10:09', due: '16 мая', desc: 'Дубль' },
  { id: 42, clientId: 6,  parent: 'Павел',     student: 'Матвей', type: 'lesson', amount: 1800,  method: 'Наличные', status: 'paid', date: '5 мая, 14:00', due: '05 мая', desc: '' },
  { id: 41, clientId: 6,  parent: 'Павел',     student: 'Матвей', type: 'lesson', amount: 1800,  method: 'СБП',   status: 'paid',    date: '30 апр, 11:10', due: '30 апр', desc: '' },
  { id: 40, clientId: 4,  parent: 'Мадина',    student: 'София',  type: 'pack',   amount: 20000, method: null,    status: 'overdue', date: '27 апр, 14:24', due: '05 мая', desc: 'Пакет 10 занятий' },
  { id: 39, clientId: 4,  parent: 'Мадина',    student: 'София',  type: 'custom', amount: 30000, method: null,    status: 'pending', date: '27 апр, 14:22', due: '10 июн', desc: 'Индивидуальный пакет' },
  { id: 38, clientId: 5,  parent: 'Екатерина', student: 'Артём',  type: 'lesson', amount: 1800,  method: 'СБП',   status: 'paid',    date: '23 апр, 11:57', due: '23 апр', desc: '' },
  { id: 37, clientId: 5,  parent: 'Екатерина', student: 'Артём',  type: 'lesson', amount: 1800,  method: 'Карта', status: 'paid',    date: '16 апр, 13:39', due: '16 апр', desc: '' },
  { id: 36, clientId: 4,  parent: 'Мадина',    student: 'София',  type: 'pack',   amount: 10000, method: null,    status: 'pending', date: '14 апр, 12:36', due: '20 апр', desc: '' },
  { id: 35, clientId: 3,  parent: 'Фаяз',      student: 'Данияр', type: 'lesson', amount: 1800,  method: 'Перевод', status: 'refund', date: '11 апр, 13:11', due: '11 апр', desc: 'Возврат за пропуск' },
];

const EXPENSES = [
  { id: 9, category: 'Аренда',   title: 'Офис, май',          amount: 45000, method: 'Перевод', date: '01 мая' },
  { id: 8, category: 'Реклама',  title: 'Яндекс Директ',     amount: 28000, method: 'Карта',   date: '03 мая' },
  { id: 7, category: 'Сервисы',  title: 'CRM и хостинг',       amount: 4900,  method: 'Карта',   date: '05 мая' },
  { id: 6, category: 'Реклама',  title: 'Telegram Ads',           amount: 15000, method: 'Карта',   date: '08 мая' },
  { id: 5, category: 'Оборудование', title: 'Веб-камеры ×2',  amount: 12000, method: 'Наличные', date: '12 мая' },
];

const PAYOUTS = [
  { id: 4, teacherId: 1, teacher: 'Гончаренко Виталий Вадимович', lessons: 48, rate: 900, amount: 43200, status: 'paid',    date: '30 апр' },
  { id: 3, teacherId: 2, teacher: 'Гневанова Анна Алексеевна', lessons: 32, rate: 900, amount: 28800, status: 'pending', date: 'за май' },
  { id: 2, teacherId: 1, teacher: 'Гончаренко Виталий Вадимович', lessons: 60, rate: 900, amount: 54000, status: 'pending', date: 'за май' },
];

// История выплат сотрудникам (записывается из модалки выплаты).
const PAYOUT_HISTORY = [
  { id: 1, teacherId: 1, teacher: 'Гончаренко Виталий Вадимович', period: '1–30 апр', lessons: 48, rate: 900, amount: 43200, status: 'paid', payDate: '30 апр 2026', method: 'Перевод', comment: '' },
  { id: 12, teacherId: 1, teacher: 'Гончаренко Виталий Вадимович', period: '1–31 мар', lessons: 52, rate: 900, amount: 46800, status: 'paid', payDate: '31 мар 2026', method: 'СБП', comment: '' },
  { id: 13, teacherId: 1, teacher: 'Гончаренко Виталий Вадимович', period: '1–28 фев', lessons: 44, rate: 900, amount: 39600, status: 'paid', payDate: '28 фев 2026', method: 'СБП', comment: '' },
  { id: 14, teacherId: 1, teacher: 'Гончаренко Виталий Вадимович', period: '1–31 янв', lessons: 39, rate: 900, amount: 35100, status: 'paid', payDate: '31 янв 2026', method: 'Карта', comment: 'С новогодними каникулами' },
  { id: 15, teacherId: 1, teacher: 'Гончаренко Виталий Вадимович', period: '1–31 мая', lessons: 60, rate: 900, amount: 54000, status: 'planned', payDate: '—', method: 'СБП', comment: '' },
  { id: 2, teacherId: 2, teacher: 'Гневанова Анна Алексеевна', period: '1–31 мар', lessons: 40, rate: 900, amount: 36000, status: 'paid', payDate: '31 мар 2026', method: 'Карта', comment: '' },
  { id: 16, teacherId: 2, teacher: 'Гневанова Анна Алексеевна', period: '1–30 апр', lessons: 36, rate: 900, amount: 32400, status: 'paid', payDate: '30 апр 2026', method: 'Карта', comment: '' },
  { id: 17, teacherId: 2, teacher: 'Гневанова Анна Алексеевна', period: '1–31 мая', lessons: 32, rate: 900, amount: 28800, status: 'planned', payDate: '—', method: 'Карта', comment: '' },
];

const LEADS = [
  { id: 24, name: 'Алина',    channel: 'telegram', contact: '@alina_wants_py', contacts: [{ type: 'telegram', value: '@alina_wants_py' }, { type: 'phone', value: '+7 (916) 240-11-08' }], goal: 'Подготовка к ОГЭ', subject: 'Python', price: 1800,  priceUnit: 'зан', manager: null,          date: 'сегодня, 10:12', converted: false },
  { id: 23, name: 'Родитель Тимура', channel: 'phone', contact: '+7 916 500-40-30', contacts: [{ type: 'phone', value: '+7 (916) 500-40-30' }], goal: 'Хочет пробное', subject: 'C++', price: 20000, priceUnit: 'мес', manager: '@pavelproga', date: 'вчера, 19:40', converted: false },
  { id: 22, name: 'Клиент 5', channel: 'phone',    contact: '457535',        contacts: [{ type: 'phone', value: '457535' }], goal: 'ацу',         subject: 'C++',    price: 25000, priceUnit: 'мес', manager: '@pavelproga', date: '7 апр, 14:34', converted: true },
  { id: 21, name: 'Клиент 4', channel: 'phone',    contact: '124241142241',  contacts: [{ type: 'phone', value: '124241142241' }], goal: 'Прогать',     subject: 'Python', price: 2600,  priceUnit: 'зан', manager: null,          date: '7 апр, 14:28', converted: false },
  { id: 20, name: 'Клиент 3', channel: 'phone',    contact: '23е5е2356е23',  contacts: [{ type: 'phone', value: '23е5е2356е23' }], goal: 'Не указана',  subject: 'C++',    price: 20000, priceUnit: 'мес', manager: null,          date: '7 апр, 14:20', converted: false },
  { id: 19, name: 'Клиент 2', channel: 'phone',    contact: 'hsrthrs',       contacts: [{ type: 'phone', value: 'hsrthrs' }], goal: '4wrer',       subject: 'Python', price: null,  priceUnit: null,  manager: '@artpawel',   date: '7 апр, 13:46', converted: true },
  { id: 18, name: 'Клиент 1', channel: 'telegram', contact: '@username',     contacts: [{ type: 'telegram', value: '@username' }], goal: '—',           subject: 'C++',    price: null,  priceUnit: null,  manager: '@admin',      date: '6 апр, 18:22', converted: true },
];

// ---- Настройки (редактируемые справочники) ----
// Дефолтная цена занятия — единственный «последний рубеж», когда у пары «ученик × педагог»
// ещё не проставлена своя цена (teacherPrices). Настраивается в Настройках (см. BACKLOG: defaultLessonPrice).
const DEFAULT_LESSON_PRICE = 1800;
window.DEFAULT_LESSON_PRICE = DEFAULT_LESSON_PRICE;
const SETTINGS = {
  defaultLessonPrice: DEFAULT_LESSON_PRICE,
  defaultCountry: '+7',
};
const TEACHER_POSITIONS = ['Стажёр', 'Преподаватель', 'Старший преподаватель', 'Методист'];
const MANAGER_POSITIONS = ['Переписки', 'Звонки', 'Продажи', 'Руководитель отдела'];
// Роли сотрудников по умолчанию (настраиваются в Настройки → Сотрудники).
// kind: 'teacher' → форма преподавателя; 'account' → форма с логином (менеджер/админ).
const STAFF_ROLES = [
  { value: 'teacher', label: 'Преподаватель', kind: 'teacher' },
  { value: 'manager', label: 'Менеджер', kind: 'account' },
  { value: 'admin', label: 'Администратор', kind: 'account' },
];

// === ВРЕМЕННЫЙ СБРОС ДАННЫХ: пустой старт для заполнения с нуля ===
// Чтобы вернуть демо-данные — удалите этот блок.
CLIENTS.length = 0;
LEADS.length = 0;
INVOICES.length = 0;
EXPENSES.length = 0;
PAYOUTS.length = 0;
PAYOUT_HISTORY.length = 0;
Object.keys(SCHEDULE).forEach(k => delete SCHEDULE[k]);
// === /СБРОС ===

const NAV = [
  { id: 'dashboard', icon: 'layout-dashboard', label: 'Дашборд' },
  { id: 'leads',     icon: 'inbox',            label: 'Заявки',  count: LEADS.length },
  { id: 'clients',   icon: 'users',            label: 'Клиенты', count: CLIENTS.filter(c => !c.archived).length },
  { id: 'payments',  icon: 'wallet',           label: 'Счета и Финансы' },
  { id: 'staff',     icon: 'briefcase',        label: 'Сотрудники', count: STAFF.filter(s => s.status === 'active').length },
  { id: 'schedule',  icon: 'calendar',         label: 'Расписание' },
];

window.CRM_DATA = { CLIENTS, LEADS, NAV, DIRECTIONS, SOURCES, CONTACT_TYPES, INVOICES, INVOICE_TYPES, INVOICE_TYPE_SHORT, PAYMENT_METHODS, EXPENSES, EXPENSE_CATEGORIES, PAYOUTS, STAFF, SETTINGS, TEACHER_POSITIONS, MANAGER_POSITIONS, STAFF_ROLES, SCHEDULE, LESSON_STATUS, PAYOUT_HISTORY, get MANAGERS() { return deriveManagers(); }, get TEACHERS() { return deriveTeachers(); } };

// ============================================================
//  ПЕРСИСТЕНТНОСТЬ: записи пользователя сохраняются между обновлениями страницы.
//  Всё, что вносится в интерфейсе (заявки, клиенты, сотрудники, занятия, выплаты…),
//  пишется в localStorage и восстанавливается при загрузке. Сброс к пустому старту —
//  кнопкой в Настройках или localStorage.removeItem('gen_crm_state_v1').
// ============================================================
const CRM_PERSIST_KEY = 'gen_crm_state_v1';
function snapshotCRM() {
  const D = window.CRM_DATA;
  // Клиенты: включаем непубличные __lessons и ledgerLog (изменения статусов/штрафов/журнала).
  const clients = (D.CLIENTS || []).map(c => { const o = Object.assign({}, c); if (c.__lessons) o.__lessons = c.__lessons; return o; });
  return JSON.stringify({
    v: 1, CLIENTS: clients, LEADS: D.LEADS, STAFF: D.STAFF, INVOICES: D.INVOICES,
    EXPENSES: D.EXPENSES, PAYOUTS: D.PAYOUTS, PAYOUT_HISTORY: D.PAYOUT_HISTORY,
    SCHEDULE: D.SCHEDULE, SETTINGS: D.SETTINGS, DIRECTIONS: D.DIRECTIONS, SOURCES: D.SOURCES,
  });
}
function saveCRM() { try { localStorage.setItem(CRM_PERSIST_KEY, snapshotCRM()); } catch (e) {} }
function loadCRM() {
  let raw; try { raw = localStorage.getItem(CRM_PERSIST_KEY); } catch (e) { return; }
  if (!raw) return;
  let s; try { s = JSON.parse(raw); } catch (e) { return; }
  const D = window.CRM_DATA;
  const fill = (arr, data) => { if (Array.isArray(data) && arr) { arr.length = 0; data.forEach(x => arr.push(x)); } };
  fill(D.CLIENTS, s.CLIENTS);
  // Восстанавливаем __lessons как НЕперечисляемое поле (как создаёт ensureClientLessons).
  (D.CLIENTS || []).forEach(c => { if (c.__lessons) { const l = c.__lessons; delete c.__lessons; Object.defineProperty(c, '__lessons', { value: l, enumerable: false, writable: true, configurable: true }); } });
  fill(D.LEADS, s.LEADS); fill(D.STAFF, s.STAFF); fill(D.INVOICES, s.INVOICES);
  fill(D.EXPENSES, s.EXPENSES); fill(D.PAYOUTS, s.PAYOUTS); fill(D.PAYOUT_HISTORY, s.PAYOUT_HISTORY);
  fill(D.DIRECTIONS, s.DIRECTIONS); fill(D.SOURCES, s.SOURCES);
  if (s.SCHEDULE && D.SCHEDULE) { Object.keys(D.SCHEDULE).forEach(k => delete D.SCHEDULE[k]); Object.assign(D.SCHEDULE, s.SCHEDULE); }
  if (s.SETTINGS && D.SETTINGS) Object.assign(D.SETTINGS, s.SETTINGS);
}
function resetCRM() { try { localStorage.removeItem(CRM_PERSIST_KEY); } catch (e) {} location.reload(); }
window.saveCRM = saveCRM; window.resetCRM = resetCRM;
// Миграция цен: у каждого клиента с педагогом гарантируем teacherPrices (вариант C).
// Источник цены — старый lessonPrice (если был), иначе DEFAULT_LESSON_PRICE. Закрывает старые сиды и localStorage.
function migrateTeacherPrices() {
  (window.CRM_DATA.CLIENTS || []).forEach(c => {
    const ts = (c.teachers && c.teachers.length) ? c.teachers : (c.teacher ? [c.teacher] : []);
    if (!ts.length) return;
    c.teacherPrices = c.teacherPrices || {};
    const def = (c.lessonPrice && parseInt(c.lessonPrice, 10)) || DEFAULT_LESSON_PRICE;
    ts.forEach(t => { if (!(parseInt(c.teacherPrices[t], 10) > 0)) c.teacherPrices[t] = def; });
  });
}
window.migrateTeacherPrices = migrateTeacherPrices;
loadCRM();                                   // восстановить сохранённое состояние
migrateTeacherPrices();                      // пролечить старые записи (сиды + localStorage) на teacherPrices
setInterval(saveCRM, 1200);                  // автосохранение
window.addEventListener('beforeunload', saveCRM);
document.addEventListener('visibilitychange', () => { if (document.hidden) saveCRM(); });
