// =======================================================================
// MariusVPN Franchise — Data layer (mock + real API).
// Spec endpoints exactly. MOCK=true returns realistic test data scoped
// to a single franchise (server is supposed to scope on its side).
// =======================================================================

const MOCK = false;  // real backend; set true only for standalone preview
const API_BASE = "/api/franchise";

// Mock-side toggles for permission demonstration (owner controls these
// from the admin panel; here we just simulate the response).
const FR_PERMS = /*EDITMODE-BEGIN*/{
  "allow_grant_days": true,
  "allow_promo": false,
  "username": "speedvpn",
  "password": "demo"
}/*EDITMODE-END*/;

async function frApi(path, { method = 'GET', body } = {}) {
  if (MOCK) return mockFrApi(path, method, body);
  const res = await fetch(API_BASE + path, {
    method,
    credentials: 'include',
    headers: { 'Content-Type': 'application/json' },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (res.status === 401) { const e = new Error('unauthorized'); e.code = 401; throw e; }
  if (res.status === 403) { const e = new Error('forbidden');    e.code = 403; throw e; }
  if (!res.ok)             { const e = new Error('http ' + res.status); e.code = res.status; throw e; }
  const ct = res.headers.get('content-type') || '';
  return ct.includes('application/json') ? res.json() : res.text();
}

// --------------- Helpers --------------------------------------------------

const RUBfr = (n) => new Intl.NumberFormat('ru-RU', { maximumFractionDigits: 0 }).format(Math.round(n)) + ' ₽';
const NUMfr = (n) => new Intl.NumberFormat('ru-RU').format(n);
const DATEfr = (iso) => new Date(iso).toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit', year: '2-digit' });
const DATETIMEfr = (iso) => new Date(iso).toLocaleString('ru-RU', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });

function daysAheadISOfr(d) { const dt = new Date(); dt.setDate(dt.getDate() + d); return dt.toISOString(); }
function daysAgoISOfr(d)   { const dt = new Date(); dt.setDate(dt.getDate() - d); return dt.toISOString(); }

// --------------- Mock store ----------------------------------------------

let FR_SESSION = { authed: false, username: null };

const FR_FIRSTS = ['Алексей','Дмитрий','Иван','Сергей','Андрей','Михаил','Артём','Никита','Павел','Роман','Анна','Мария','Екатерина','Юлия','Ольга','Татьяна','Полина','Виктория','Дарья','Алиса'];
const FR_LASTS  = ['Иванов','Петров','Соколов','Смирнов','Кузнецов','Новиков','Морозов','Волков','Лебедев','Орлов'];
const FR_USERNAMES = ['marius','crypto_kid','dnyper','sokolova','volk7','andreyk','katya_p','romka','niki_t','art_kov','olga99','dasha_x','polina_b','vika__','tatyana_l','m_serg','ivan_iv','pasha_r','nik_b','alina_z'];

function frSeed(seed) { let s = seed; return () => { s = (s * 9301 + 49297) % 233280; return s / 233280; }; }
const frRnd = frSeed(73);
const frPick = (arr) => arr[Math.floor(frRnd() * arr.length)];

const FR_USERS = (() => {
  const arr = [];
  for (let i = 0; i < 84; i++) {
    const fn = frPick(FR_FIRSTS), ln = frPick(FR_LASTS);
    const expIn = Math.floor(frRnd() * 60) - 8;
    arr.push({
      id: 200000 + i,
      tg_id: 1100000000 + Math.floor(frRnd() * 800000000),
      tg_username: frPick(FR_USERNAMES) + (frRnd() < 0.5 ? '' : String(Math.floor(frRnd()*99))),
      tg_name: `${fn} ${ln[0]}.`,
      balance: Math.floor(frRnd() * 1200),
      days_left: expIn,
      expire_at: daysAheadISOfr(expIn),
      topups_count: Math.floor(frRnd() * 12),
      is_blocked: frRnd() < 0.04,
    });
  }
  return arr;
})();

const frUserStatus = (u) => u.is_blocked ? 'blocked' : (u.days_left <= 0 ? 'expired' : 'active');

const FR_BROADCAST_JOBS = [
  { id: 312, status: 'sent',      sent: 78,  failed: 1, created_at: daysAgoISOfr(0) },
  { id: 311, status: 'sending',   sent: 41,  failed: 0, created_at: daysAgoISOfr(0) },
  { id: 310, status: 'sent',      sent: 80,  failed: 2, created_at: daysAgoISOfr(2) },
  { id: 309, status: 'sent',      sent: 74,  failed: 0, created_at: daysAgoISOfr(6) },
  { id: 308, status: 'failed',    sent: 0,   failed: 0, created_at: daysAgoISOfr(8) },
];

const FR_WITHDRAWALS = [
  { id: 24, amount: 8000,  status: 'paid',     details: 'Сбер ····4421',     created_at: daysAgoISOfr(5)  },
  { id: 23, amount: 12000, status: 'paid',     details: 'TON UQDx…42pq',     created_at: daysAgoISOfr(18) },
  { id: 22, amount: 5400,  status: 'rejected', details: 'Тинькофф ····2210', created_at: daysAgoISOfr(26) },
  { id: 21, amount: 9200,  status: 'paid',     details: 'Сбер ····4421',     created_at: daysAgoISOfr(33) },
];

const FR_SETTINGS = {
  price: 249,
  min_price: 199,
  brand_color: '#22D3EE',
  welcome_text: 'Добро пожаловать в SpeedVPN!\nБыстро, надёжно, без логов. 3 дня пробного периода — бесплатно.',
  banners: [
    { id: 1, title: 'Новогодняя скидка',    body: '−30% на год при оплате до 31.12',  active: true  },
    { id: 2, title: 'Реферальная программа', body: 'Приведи друга — получи 7 дней',    active: true  },
    { id: 3, title: 'Stories-бонус',         body: 'Отметь нас в Stories — +3 дня',   active: false },
  ],
  required_channel_username: '@speedvpn_news',
  review_url: 'https://t.me/c/123456/9',
  review_text: 'Спасибо! Если нравится сервис — оставьте, пожалуйста, отзыв в нашем канале.',
  stories_bonus_enabled: true,
};

const FR_DASH = () => {
  const users = FR_USERS.length;
  const active = FR_USERS.filter(u => frUserStatus(u) === 'active').length;
  const revenue = 142800;       // за всё время для франшизы
  const revenue_month = 38400;
  const balance = 14820;        // доступно к выводу
  const payouts_total = 89000;
  const share_percent = 50;
  return { users, users_active: active, revenue, revenue_month, balance, payouts_total, share_percent };
};

// --------------- Mock router ----------------------------------------------

async function mockFrApi(path, method, body) {
  await new Promise(r => setTimeout(r, 140 + Math.random() * 200));

  // auth
  if (path === '/whoami') {
    if (!FR_SESSION.authed) { const e = new Error('unauthorized'); e.code = 401; throw e; }
    return { username: FR_SESSION.username, franchise_name: 'SpeedVPN', bot_username: '@speedvpn_bot' };
  }
  if (path === '/login' && method === 'POST') {
    if (body && body.username === FR_PERMS.username && body.password === FR_PERMS.password) {
      FR_SESSION = { authed: true, username: body.username };
      return { ok: true };
    }
    const e = new Error('Неверный логин или пароль'); e.code = 401; throw e;
  }
  if (path === '/logout' && method === 'POST') { FR_SESSION = { authed: false, username: null }; return { ok: true }; }

  if (!FR_SESSION.authed) { const e = new Error('unauthorized'); e.code = 401; throw e; }

  // dashboard
  if (path === '/dashboard' && method === 'GET') return FR_DASH();

  // users list
  const usersMatch = path.match(/^\/users(\?.*)?$/);
  if (usersMatch && method === 'GET') {
    const q = new URLSearchParams((usersMatch[1] || '').slice(1));
    const query = (q.get('query') || '').toLowerCase();
    const status = q.get('status') || '';
    const page = parseInt(q.get('page') || '1', 10);

    let items = FR_USERS.filter(u => {
      if (query && !((u.tg_username || '').toLowerCase().includes(query) || (u.tg_name || '').toLowerCase().includes(query) || String(u.id).includes(query) || String(u.tg_id).includes(query))) return false;
      if (status && frUserStatus(u) !== status) return false;
      return true;
    });
    const total = items.length;
    const PAGE = 25;
    items = items.slice((page - 1) * PAGE, page * PAGE);
    return { total, items, page, page_size: PAGE };
  }

  // user detail
  const singleMatch = path.match(/^\/users\/(\d+)$/);
  if (singleMatch && method === 'GET') {
    const id = parseInt(singleMatch[1], 10);
    const u = FR_USERS.find(x => x.id === id);
    if (!u) { const e = new Error('not found'); e.code = 404; throw e; }
    // topups
    const topups = [];
    const n = 3 + (id % 5);
    for (let i = 0; i < n; i++) {
      topups.push({
        amount: frPick([149, 249, 399, 699, 1290]),
        status: frRnd() < 0.9 ? 'paid' : (frRnd() < 0.5 ? 'pending' : 'failed'),
        method: frPick(['ЮKassa', 'CryptoBot', 'TON Space', 'Telegram Stars']),
        created_at: daysAgoISOfr(Math.floor(frRnd() * 90)),
      });
    }
    return { ...u, topups: topups.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) };
  }

  // message — always allowed
  const msgMatch = path.match(/^\/users\/(\d+)\/message$/);
  if (msgMatch && method === 'POST') return { ok: true };

  // grant-days — gated
  const grantMatch = path.match(/^\/users\/(\d+)\/grant-days$/);
  if (grantMatch && method === 'POST') {
    if (!FR_PERMS.allow_grant_days) { const e = new Error('forbidden'); e.code = 403; throw e; }
    const id = parseInt(grantMatch[1], 10);
    const u = FR_USERS.find(x => x.id === id);
    if (!u) { const e = new Error('not found'); e.code = 404; throw e; }
    u.days_left += body.days;
    u.expire_at = daysAheadISOfr(u.days_left);
    return { ok: true };
  }

  // promo — gated
  const promoMatch = path.match(/^\/users\/(\d+)\/give-promo$/);
  if (promoMatch && method === 'POST') {
    if (!FR_PERMS.allow_promo) { const e = new Error('forbidden'); e.code = 403; throw e; }
    return { ok: true, code: 'GIFT-' + Math.random().toString(36).slice(2, 8).toUpperCase() };
  }

  // broadcast
  if (path === '/broadcast/jobs' && method === 'GET') return FR_BROADCAST_JOBS;
  if (path === '/broadcast' && method === 'POST') {
    const id = Math.max(...FR_BROADCAST_JOBS.map(j => j.id)) + 1;
    FR_BROADCAST_JOBS.unshift({ id, status: 'sending', sent: 0, failed: 0, created_at: new Date().toISOString() });
    return { ok: true, id };
  }

  // settings
  if (path === '/settings' && method === 'GET') return { ...FR_SETTINGS };
  if (path === '/settings' && method === 'PUT') {
    // server-side clamp: never below min_price
    if (body.price != null && body.price < FR_SETTINGS.min_price) body.price = FR_SETTINGS.min_price;
    Object.assign(FR_SETTINGS, body);
    return { ok: true, settings: { ...FR_SETTINGS } };
  }

  // withdrawals
  if (path === '/withdrawals' && method === 'GET') return FR_WITHDRAWALS;
  if (path === '/withdraw' && method === 'POST') {
    const dash = FR_DASH();
    if (body.amount > dash.balance) { const e = new Error('Сумма превышает доступный баланс'); e.code = 400; throw e; }
    const id = Math.max(...FR_WITHDRAWALS.map(w => w.id)) + 1;
    FR_WITHDRAWALS.unshift({ id, amount: body.amount, status: 'pending', details: body.details, created_at: new Date().toISOString() });
    return { ok: true, id };
  }

  throw new Error('mock: not handled ' + method + ' ' + path);
}

window.FR_API = { frApi, MOCK, FR_PERMS, RUBfr, NUMfr, DATEfr, DATETIMEfr, frUserStatus };
