/**
 * Shared helpers cho Alpine components
 */
import { formatDate as _formatDate } from './utils/date';

export { _formatDate as formatDate };
export { formatDateTime, formatTime } from './utils/date';

export function getCsrfToken() {
    return document.querySelector('meta[name="csrf-token"]')?.content || '';
}

export function escapeHtml(value) {
    const div = document.createElement('div');
    div.textContent = value === null || value === undefined ? '' : String(value);
    return div.innerHTML;
}

export function formatNumber(value) {
    const num = Number(value || 0);
    return Number.isFinite(num) ? num.toLocaleString('vi-VN') : '0';
}

export function formatCurrency(value) {
    if (value === null || value === undefined || value === '') return '-';
    const num = Number(value);
    if (!Number.isFinite(num)) return '-';
    if (num === 0) return 'Freecast';
    return Math.floor(num).toLocaleString('vi-VN');
}

/**
 * Format tiền dạng gọn bằng chữ (compact): 1.2B / 3.4M / 5.6K.
 * Dùng cho giá trị tổng ở tâm biểu đồ donut (dashboard + gm-theo-kênh creator).
 */
export function formatMoneyCompact(value) {
    const num = Number(value || 0);
    if (!Number.isFinite(num)) return '0';
    if (num >= 1e9) return (num / 1e9).toFixed(1).replace(/\.0$/, '') + 'B';
    if (num >= 1e6) return (num / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
    if (num >= 1e3) return (num / 1e3).toFixed(1).replace(/\.0$/, '') + 'K';
    return num.toLocaleString('vi-VN');
}

export function cleanNumberInput(value) {
    const text = String(value || '').replace(/[^0-9]/g, '');
    return text === '' ? null : Number(text);
}

/**
 * Format số trong khi nhập: chỉ cho phép số và dấu "," (thập phân),
 * tự động thêm "." mỗi 3 số ở phần nguyên
 */
export function formatNumberTyping(value) {
    if (!value && value !== 0) return '';
    let str = String(value);

    str = str.replace(/[^0-9,]/g, '');

    const commaIdx = str.indexOf(',');
    if (commaIdx !== -1) {
        str = str.substring(0, commaIdx + 1) + str.substring(commaIdx + 1).replace(/,/g, '');
    }

    const parts = str.split(',');
    let intPart = parts[0].replace(/\./g, '');

    let result = '';
    for (let i = 0; i < intPart.length; i++) {
        if (i > 0 && (intPart.length - i) % 3 === 0) {
            result += '.';
        }
        result += intPart[i];
    }

    if (parts.length > 1) {
        result += ',' + parts[1];
    }

    return result;
}

/**
 * Chuyển số đã format (vd: "1.000.000,5") về dạng raw string "1000000.5"
 */
export function unformatNumber(value) {
    if (value === null || value === undefined || value === '') return '';
    return String(value).replace(/\./g, '').replace(',', '.');
}

/**
 * Clean số đã format thành dạng number để gửi lên API
 */
export function cleanNumberForSubmit(value) {
    if (value === null || value === undefined || value === '') return null;
    const str = unformatNumber(value);
    const num = parseFloat(str);
    return isNaN(num) ? null : num;
}

/**
 * Xử lý sự kiện input cho trường số có format:
 * - Format hiển thị
 * - Giữ đúng vị trí con trỏ
 */
export function onNumberInput(event) {
    const input = event.target;
    if (!input || typeof input.value !== 'string') return;

    const cursorPos = input.selectionStart;
    const rawBefore = input.value.substring(0, cursorPos).replace(/\./g, '').length;

    const formatted = formatNumberTyping(input.value);
    input.value = formatted;

    let newPos = 0;
    let rawSeen = 0;
    for (let i = 0; i < formatted.length && rawSeen < rawBefore; i++) {
        newPos = i + 1;
        if (formatted[i] !== '.') rawSeen++;
    }
    if (rawSeen < rawBefore) newPos = formatted.length;

    try { input.setSelectionRange(newPos, newPos); } catch (e) { /* noop */ }
}

export async function requestJson(url, options = {}) {
    const csrf = getCsrfToken();
    const response = await fetch(url, {
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
            'X-CSRF-TOKEN': csrf,
        },
        credentials: 'same-origin',
        ...options,
    });

    const data = await response.json().catch(() => ({}));

    if (!response.ok) {
        const error = new Error(data?.message || 'Request failed');
        error.data = data;
        throw error;
    }

    return data;
}

export async function fetchJson(url, options = {}) {
    const response = await fetch(url, {
        headers: {
            Accept: 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
        },
        credentials: 'same-origin',
        ...options,
    });

    if (!response.ok) {
        throw new Error(`Request failed: ${response.status}`);
    }

    return response.json();
}

export function buildQuery(params) {
    const sp = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
        if (value === null || value === undefined || value === '') return;
        if (Array.isArray(value)) {
            value.forEach(item => { if (item) sp.append(key + '[]', item); });
            return;
        }
        sp.set(key, String(value));
    });
    return sp.toString();
}

const STAT_CARD_ICONS = {
    'Tổng KOC': '👥',
    'KOC có SDT': '📞',
    'KOC có Facebook': '👍',
    'KOC có Instagram': '📷',
    'KOC có Gmail': '📧',
    'KOC có thể liên hệ ngay': '📱',
    'KOC đã vào chiến dịch': '📋',
    'KOC chưa vào chiến dịch': '⏳',
    'Tổng số chiến dịch': '🎯',
    'Chiến dịch đang chạy': '🚀',
    'Tổng KOC trong tất cả chiến dịch': '👥',
    'Tổng chi phí cast': '💵',
    'Tổng chi phí mẫu': '🎁',
    'Tổng chi phí ship': '🚚',
    'Tổng 3 chi phí': '💰',
    // English keys (fallback)
    'total_campaigns': '🎯',
    'running_campaigns': '🚀',
    'total_kocs': '👥',
    'total_cast_cost': '💵',
    'total_sample_cost': '🎁',
    'total_shipping_cost': '🚚',
    'total_all_costs': '💰',
};

function guessStatIcon(label) {
    return STAT_CARD_ICONS[label] || '📊';
}

export function renderStatsCards(containerId, metrics = {}) {
    const container = document.getElementById(containerId);
    if (!container || !metrics) return;

    const entries = Object.entries(metrics);
    if (entries.length === 0) {
        container.innerHTML = '<div class="stat-card"><div class="stat-card-content"><div class="stat-label">Chưa có dữ liệu</div><div class="stat-value">-</div></div></div>';
        return;
    }

    container.innerHTML = entries.map(([label, value]) => {
        const formatted = typeof value === 'number' ? value.toLocaleString('vi-VN') : value;
        const icon = guessStatIcon(label);
        return '<div class="stat-card"><div class="stat-card-content"><div class="stat-label">' + escapeHtml(label) + '</div><div class="stat-value">' + escapeHtml(formatted) + '</div></div><div class="stat-icon">' + icon + '</div></div>';
    }).join('');
}

/**
 * Tạo HTML cho KPI card dạng stat-card — hiện không dùng (chuyển sang Blade Alpine)
 * @param {Object} card - { label, icon, value, sub, delta? }
 * @returns {string} HTML string
 */
export function buildKpiCardHtml(card) {
    let trendHtml = '';
    if (card.delta !== null && card.delta !== undefined) {
        const cls = card.delta > 0 ? 'up' : card.delta < 0 ? 'down' : 'flat';
        const arrow = card.delta > 0 ? '▲' : card.delta < 0 ? '▼' : '—';
        trendHtml = `<span class="stat-trend ${cls}">${arrow} ${Math.abs(card.delta).toLocaleString('vi-VN')}</span>`;
    }
    const val = card.value ?? 0;
    const formatted = typeof val === 'number' ? val.toLocaleString('vi-VN') : val;
    const iconHtml = card.icon ? `<div class="stat-icon">${card.icon}</div>` : '';
    return `<div class="stat-card db-activity-card">
  <div class="stat-card-content">
    <div class="stat-label">${escapeHtml(card.label)}</div>
    <div class="stat-value">${formatted}</div>
    <div class="stat-footer">${escapeHtml(card.sub || '')}${trendHtml}</div>
  </div>${iconHtml}</div>`;
}

/**
 * Tạo HTML hiển thị các icon social links (TikTok, Facebook, Instagram)
 * @param {Object} data - Object chứa tiktok_link, facebook_link, instagram_link
 * @returns {string} HTML string
 */
export function buildSocialLinksHtml(data) {
    const links = [];
    if (data?.tiktok_link) links.push('<a href="' + escapeHtml(data.tiktok_link) + '" target="_blank" rel="noopener noreferrer" class="social-link-icon"><img src="/images/icons/tiktok.svg" alt="TikTok" /></a>');
    if (data?.facebook_link) links.push('<a href="' + escapeHtml(data.facebook_link) + '" target="_blank" rel="noopener noreferrer" class="social-link-icon"><img src="/images/icons/Facebook.svg" alt="Facebook" /></a>');
    if (data?.instagram_link) links.push('<a href="' + escapeHtml(data.instagram_link) + '" target="_blank" rel="noopener noreferrer" class="social-link-icon"><img src="/images/icons/instagram.svg" alt="Instagram" /></a>');
    return links.length ? '<span class="social-links-wrap">' + links.join('') + '</span>' : '-';
}

/**
 * Tạo HTML nút liên hệ với data attribute
 * @param {Object} data - Object chứa contact_phone, contact_zalo, contact_email, address
 * @returns {string} HTML string hoặc '-' nếu không có dữ liệu
 */
export function buildContactButtonHtml(data) {
    const hasAny = data?.contact_phone || data?.contact_zalo || data?.contact_email || data?.address;
    if (!hasAny) return '-';
    const parts = [];
    if (data.contact_phone) parts.push('data-phone="' + escapeHtml(data.contact_phone) + '"');
    if (data.contact_zalo) parts.push('data-zalo="' + escapeHtml(data.contact_zalo) + '"');
    if (data.contact_email) parts.push('data-email="' + escapeHtml(data.contact_email) + '"');
    if (data.address) parts.push('data-address="' + escapeHtml(data.address) + '"');
    return '<button type="button" class="contact-toggle-btn" ' + parts.join(' ') + ' aria-expanded="false" aria-label="Xem liên hệ">&#x1F4F1;</button>';
}

/**
 * Tạo badge HTML cho phân loại KOC (Nano/Micro/Macro)
 * @param {string} classification - 'Nano KOC', 'Micro KOC', 'Macro KOC' hoặc ''
 * @returns {string} HTML badge
 */
export function buildClassificationBadgeHtml(classification) {
    if (!classification) return '-';
    const map = {
        'Nano KOC': 'classification-badge--nano',
        'Micro KOC': 'classification-badge--micro',
        'Macro KOC': 'classification-badge--macro',
    };
    const cssClass = map[classification] || '';
    return '<span class="classification-badge ' + cssClass + '">' + classification + '</span>';
}

/**
 * Tạo HTML hiển thị mô tả với nút xem popover
 * @param {string} description
 * @returns {string} HTML string
 */
export function buildDescriptionToggleHtml(description) {
    if (!description) return '-';
    const text = String(description);
    return '<button type="button" class="description-toggle-btn" data-desc="' + encodeURIComponent(text) + '" aria-expanded="false" aria-label="Xem mô tả">📄</button>';
}

/**
 * Khởi tạo description popover (gọi 1 lần khi app init)
 */
export function initDescriptionPopover() {
    const pop = document.createElement('div');
    pop.className = 'contact-popover description-popover hide';
    pop.setAttribute('role', 'dialog');
    pop.setAttribute('aria-hidden', 'true');
    document.body.appendChild(pop);
    let activeBtn = null;

    function show(btn) {
        const raw = decodeURIComponent(btn.dataset.desc || '');
        const formatted = escapeHtml(raw).replace(/\n/g, '<br>');
        const bulleted = formatted.replace(/(^|<br>)(?!<br>|• )/g, '$1• ');
        pop.innerHTML = '<div class="description-popover-content">' + bulleted + '</div>';
        pop.classList.remove('hide'); pop.classList.add('show');
        pop.setAttribute('aria-hidden', 'false');
        activeBtn = btn;
        btn.setAttribute('aria-expanded', 'true');
        requestAnimationFrame(() => {
            const rect = btn.getBoundingClientRect(), pRect = pop.getBoundingClientRect();
            const scrollX = window.scrollX || window.pageXOffset, scrollY = window.scrollY || window.pageYOffset;
            let left = rect.right + 8 + scrollX, top = rect.top + (rect.height / 2) - (pRect.height / 2) + scrollY;
            const viewportRight = scrollX + document.documentElement.clientWidth - 8;
            let side = 'left';
            if (left + pRect.width > viewportRight) { left = rect.left - pRect.width - 8 + scrollX; side = 'right'; }
            const minTop = scrollY + 8, maxTop = scrollY + document.documentElement.clientHeight - pRect.height - 8;
            top = Math.max(minTop, Math.min(maxTop, top));
            pop.style.left = Math.round(left) + 'px'; pop.style.top = Math.round(top) + 'px';
            const arrowTop = (rect.top + (rect.height / 2) + scrollY) - top;
            pop.style.setProperty('--arrow-top', Math.round(arrowTop) + 'px');
            pop.classList.remove('arrow-left', 'arrow-right');
            pop.classList.add(side === 'left' ? 'arrow-left' : 'arrow-right');
        });
    }

    function hide() {
        if (activeBtn) activeBtn.setAttribute('aria-expanded', 'false');
        pop.classList.remove('show'); pop.classList.add('hide');
        pop.setAttribute('aria-hidden', 'true');
        activeBtn = null;
    }

    document.addEventListener('click', (e) => {
        if (!activeBtn) return;
        if (e.target === activeBtn || activeBtn.contains(e.target) || pop.contains(e.target)) return;
        hide();
    }, true);
    ['scroll', 'resize', 'wheel', 'touchstart'].forEach(evName =>
        window.addEventListener(evName, (e) => { if (activeBtn && pop && !pop.contains(e.target)) hide(); }, { passive: true }));
    document.addEventListener('keydown', (e) => { if (e.key === 'Escape') hide(); });

    document.addEventListener('click', (e) => {
        const btn = e.target.closest('.description-toggle-btn');
        if (!btn) return;
        e.stopPropagation(); e.preventDefault();
        if (activeBtn === btn) { hide(); return; }
        hide(); show(btn);
    }, true);
}

/**
 * Khởi tạo contact popover (gọi 1 lần khi app init)
 */
export function buildStatusBadgeHtml(value, enumArray) {
    const item = (enumArray || []).find(e => e.value === value);
    if (!item) return '<span class="status-badge status-badge--draft">' + (value || '-') + '</span>';
    return '<span class="status-badge ' + item.cssClass + '">' + escapeHtml(item.label) + '</span>';
}

const VIDEO_STATUS_SHORT_LABELS = {
    pending: 'Chưa lên',
    published: 'Đã đăng',
};

export function normalizeVideoStatusValue(status) {
    const value = String(status || '').trim();
    if (['published', 'pending'].includes(value)) {
        return value;
    }
    return 'pending';
}

export function buildVideoStatusBadgeHtml(status) {
    const normalized = normalizeVideoStatusValue(status);
    const label = VIDEO_STATUS_SHORT_LABELS[normalized] || normalized;
    return '<span class="video-status-badge video-status-badge--' + normalized + '"><span class="video-status-dot"></span>' + escapeHtml(label) + '</span>';
}

export function buildVideoProgressHtml(videos, options = {}) {
    const list = Array.isArray(videos) ? videos : [];
    const total = options.expectedCount ?? list.length;
    if (total === 0) {
        const emptyClass = options.clickable ? 'video-progress-empty video-progress--clickable' : 'video-progress-empty';
        const progressClass = options.dataKocId ? ' video-progress' : '';
        const emptyAttrs = options.dataKocId ? ' data-koc-id="' + escapeHtml(String(options.dataKocId)) + '"' : '';
        return '<span class="' + emptyClass + progressClass + '"' + emptyAttrs + '>—</span>';
    }

    const counts = { published: 0, pending: 0 };
    list.forEach((video) => {
        const status = normalizeVideoStatusValue(video?.status);
        if (counts[status] !== undefined) counts[status]++;
    });
    // Thêm pending cho số slot chưa có record video nào
    if (options.expectedCount && options.expectedCount > list.length) {
        counts.pending += options.expectedCount - list.length;
    }

    const pct = (n) => (n > 0 ? Math.round((n / total) * 100) : 0);
    const segments = ['published', 'pending']
        .filter((key) => counts[key] > 0)
        .map((key) => '<div class="video-progress-bar__segment video-progress-bar__segment--' + key + '" style="width:' + pct(counts[key]) + '%"></div>')
        .join('');

    const labelClass = counts.published === total ? 'video-progress-label is-complete' : 'video-progress-label';
    const title = counts.published + ' đã đăng / ' + counts.pending + ' chưa lên';

    const wrapClasses = ['video-progress-wrap'];
    if (options.clickable || options.dataKocId) wrapClasses.push('video-progress');
    if (options.clickable) wrapClasses.push('video-progress--clickable');
    const wrapAttrs = options.dataKocId ? ' data-koc-id="' + escapeHtml(String(options.dataKocId)) + '"' : '';

    return '<div class="' + wrapClasses.join(' ') + '"' + wrapAttrs + '><div class="video-progress-bar">' + segments + '</div><span class="' + labelClass + '" title="' + escapeHtml(title) + '">' + counts.published + '/' + total + ' đăng</span></div>';
}

export function toArrayLines(value) {
    return String(value || '').split('\n').map(x => x.trim()).filter(Boolean);
}

export function toMultilineText(value) {
    if (!Array.isArray(value)) return '';
    return value.map(x => String(x || '').trim()).filter(Boolean).join('\n');
}

export function fileToDataURL(file) {
    return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.onerror = () => resolve(null);
        reader.readAsDataURL(file);
    });
}

export function initContactPopover() {
    const pop = document.createElement('div');
    pop.className = 'contact-popover hide';
    pop.setAttribute('role', 'dialog');
    pop.setAttribute('aria-hidden', 'true');
    document.body.appendChild(pop);
    let activeBtn = null;

    function show(btn) {
        const data = {
            phone: btn.dataset.phone || '',
            zalo: btn.dataset.zalo || '',
            email: btn.dataset.email || '',
            address: btn.dataset.address || '',
        };
        const lines = [];
        if (data.phone) lines.push('<div class="contact-line"><span class="contact-icon" aria-hidden="true">&#x1F4DE;</span><span class="contact-value">' + escapeHtml(data.phone) + '</span></div>');
        if (data.zalo) lines.push('<div class="contact-line"><span class="contact-icon zalo-icon" aria-hidden="true"><img src="/images/icons/zalo.svg" alt="Zalo" /></span><span class="contact-value">' + escapeHtml(data.zalo) + '</span></div>');
        if (data.email) lines.push('<div class="contact-line"><span class="contact-icon email-icon" aria-hidden="true"><img src="/images/icons/email.svg" alt="Email" /></span><span class="contact-value">' + escapeHtml(data.email) + '</span></div>');
        if (data.address) lines.push('<div class="contact-line"><span class="contact-icon" aria-hidden="true">&#x1F4CD;</span><span class="contact-value">' + escapeHtml(data.address) + '</span></div>');
        pop.innerHTML = lines.join('') || '<div class="contact-empty">Không có thông tin liên hệ</div>';
        pop.classList.remove('hide'); pop.classList.add('show'); pop.setAttribute('aria-hidden', 'false');
        activeBtn = btn; btn.setAttribute('aria-expanded', 'true');
        requestAnimationFrame(() => {
            const rect = btn.getBoundingClientRect(), pRect = pop.getBoundingClientRect();
            const scrollX = window.scrollX || window.pageXOffset, scrollY = window.scrollY || window.pageYOffset;
            let left = rect.right + 8 + scrollX, top = rect.top + (rect.height / 2) - (pRect.height / 2) + scrollY;
            const viewportRight = scrollX + document.documentElement.clientWidth - 8;
            let side = 'left';
            if (left + pRect.width > viewportRight) { left = rect.left - pRect.width - 8 + scrollX; side = 'right'; }
            const minTop = scrollY + 8, maxTop = scrollY + document.documentElement.clientHeight - pRect.height - 8;
            top = Math.max(minTop, Math.min(maxTop, top));
            pop.style.left = Math.round(left) + 'px'; pop.style.top = Math.round(top) + 'px';
            const arrowTop = (rect.top + (rect.height / 2) + scrollY) - top;
            pop.style.setProperty('--arrow-top', Math.round(arrowTop) + 'px');
            pop.classList.remove('arrow-left', 'arrow-right'); pop.classList.add(side === 'left' ? 'arrow-left' : 'arrow-right');
        });
    }

    function hide() {
        if (activeBtn) activeBtn.setAttribute('aria-expanded', 'false');
        pop.classList.remove('show'); pop.classList.add('hide'); pop.setAttribute('aria-hidden', 'true'); activeBtn = null;
    }

    document.addEventListener('click', (e) => {
        if (!activeBtn) return;
        if (e.target === activeBtn || activeBtn.contains(e.target) || pop.contains(e.target)) return;
        hide();
    }, true);
    ['scroll', 'resize', 'wheel', 'touchstart'].forEach(ev => window.addEventListener(ev, () => { if (activeBtn) hide(); }, { passive: true }));
    document.addEventListener('keydown', (e) => { if (e.key === 'Escape') hide(); });

    document.addEventListener('click', (e) => {
        const btn = e.target.closest('.contact-toggle-btn');
        if (!btn) return;
        e.stopPropagation(); e.preventDefault();
        if (activeBtn === btn) { hide(); return; }
        hide(); show(btn);
    }, true);
}

/**
 * Khởi tạo portal tooltip cho các phần tử có data-tooltip (gọi 1 lần khi app init)
 * Dùng thay thế title gốc để giới hạn chiều ngang, text dài tự xuống dòng.
 */
export function initPortalTooltip() {
    const tip = document.createElement('div');
    tip.className = 'portal-tooltip';
    tip.setAttribute('role', 'tooltip');
    tip.style.display = 'none';
    document.body.appendChild(tip);
    let active = null;

    function position(e) {
        const r = tip.getBoundingClientRect();
        const pad = 8, gap = 12;
        let left = e.clientX + gap;
        let top = e.clientY + gap;
        if (left + r.width + pad > window.innerWidth) left = e.clientX - r.width - gap;
        if (top + r.height + pad > window.innerHeight) top = e.clientY - r.height - gap;
        tip.style.left = Math.max(pad, left) + 'px';
        tip.style.top = Math.max(pad, top) + 'px';
    }

    function show(el, e) {
        tip.textContent = el.getAttribute('data-tooltip') || '';
        tip.style.display = 'block';
        active = el;
        position(e);
    }

    function hide() {
        tip.style.display = 'none';
        active = null;
    }

    document.addEventListener('mouseover', (e) => {
        const el = e.target.closest && e.target.closest('[data-tooltip]');
        if (!el) { if (active) hide(); return; }
        if (el === active) { position(e); return; }
        show(el, e);
    });
    document.addEventListener('mousemove', (e) => {
        if (active) position(e);
    });
    ['scroll', 'resize', 'wheel', 'touchstart'].forEach(ev => window.addEventListener(ev, () => { if (active) hide(); }, { passive: true }));
    document.addEventListener('keydown', (e) => { if (e.key === 'Escape') hide(); });
}

export async function downloadXlsx(filename, headers, rows) {
    const resp = await fetch('/export/xlsx', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-TOKEN': getCsrfToken(),
            'X-Requested-With': 'XMLHttpRequest',
        },
        body: JSON.stringify({ filename, headers, rows }),
    });
    if (!resp.ok) {
        let msg = `HTTP ${resp.status}`;
        try {
            const text = await resp.text().then(t => t.substring(0, 300));
            if (text) msg = text;
        } catch (_) {}
        throw new Error(msg);
    }
    const blob = await resp.blob();
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename + '.xlsx';
    a.addEventListener('click', e => e.stopPropagation());
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
}
