/**
 * Alpine Component: Creator Page
 */
import { requestJson, fetchJson, buildQuery, formatNumber, formatCurrency, renderStatsCards, cleanNumberForSubmit, downloadXlsx, formatDate } from '../helpers';
import { formatTime, formatDateTime } from '../utils/date';
import MSG from '../messages';

export function registerCreatorPage(Alpine) {
    Alpine.data('creatorPage', () => ({
        page: 1,
        pageSize: 10,
        totalItems: 0,
        totalPages: 1,
        rows: [],
        sortField: null,
        sortDirection: 'asc',
        filters: { keyword: '', contacts: [], advantages: [], followers_min: null, followers_max: null, gmv_min: null, gmv_max: null, items_min: null, items_max: null, classification: '', content: '' },
        filterExpanded: false,
        loading: false,
        selected: [],
        selectAll: false,
        editingId: null,
        deletingId: null,
        bulkCampaignId: '',
        bulkCampaigns: [],
        bulkBookingType: 'video',
        syncing: false,
        syncAborted: false,
        syncFromKoc: 1,
        syncToKoc: 0,
        syncSelectAll: true,
        syncAllKocs: true,
        syncResults: [],
        syncReviewUpdating: false,
        syncReviewUpdatedCount: 0,
        _syncSelectedFieldsSnapshot: [],
        syncFieldsList: [
            { key: 'followers', label: 'Followers', checked: true },
            { key: 'gmv', label: 'GMV', checked: true },
            { key: 'items', label: 'S.món đã bán', checked: true },
            { key: 'average_views', label: 'View video TB', checked: true },
            { key: 'advantages', label: 'Lợi thế', checked: true },
            { key: 'contact', label: 'Liên hệ', checked: true },
        ],
        showSyncProgress: false,
        syncProgressMessage: '',
        syncProgressCurrent: 0,
        syncProgressTotal: 0,
        syncProgressPercent: 0,
        syncProgressFinished: false,
        syncStats: { updated: 0, notFound: 0, missingCid: 0, errors: 0 },
        syncSessionToken: '',
        lastSyncAt: null,
        lastSyncFrom: null,
        lastSyncTo: null,
        syncDebugLogs: [],
        totalKocCount: 0,
        extensionReady: false,
        _addFormBound: false,
        _editFormBound: false,

        canExport: false,

        init() {
            const root = document.getElementById('creator-page');
            this.canExport = root?.dataset?.canExport === '1';
            this.loadMetrics();
            this.loadRows();
            this._bindAddForm();
            this._bindEditForm();
            this._detectExtension();
            this._fetchLastSync();
        },

        _fetchLastSync() {
            fetch('/api/sync/last-sync')
                .then(r => r.json())
                .then(data => {
                    if (data.lastSyncAt) {
                        this.lastSyncAt = data.lastSyncAt;
                        this.lastSyncFrom = data.lastSyncFrom;
                        this.lastSyncTo = data.lastSyncTo;
                    }
                })
                .catch(() => { });
        },

        /**
         * Phát hiện Extension đã cài chưa (qua content_webapp.js)
         */
        _detectExtension() {
            // Kiểm tra ngay (nếu extension load trước)
            if (document.getElementById('kocbooking-extension-installed')) {
                this.extensionReady = true;
                return;
            }
            // Lắng nghe sự kiện KOC_EXTENSION_READY
            window.addEventListener('KOC_EXTENSION_READY', () => {
                this.extensionReady = true;
            }, { once: true });
            // Timeout 3s nếu không phát hiện
            setTimeout(() => {
                if (!this.extensionReady && document.getElementById('kocbooking-extension-installed')) {
                    this.extensionReady = true;
                }
            }, 3000);
        },

        get startItem() { return this.totalItems === 0 ? 0 : (this.page - 1) * this.pageSize + 1; },
        get endItem() { return Math.min(this.page * this.pageSize, this.totalItems); },
        get visiblePages() {
            const pages = [];
            const s = Math.max(1, this.page - 2);
            const e = Math.min(this.totalPages, this.page + 2);
            for (let i = s; i <= e; i++) pages.push(i);
            return pages;
        },
        get selectedCount() { return this.selected.length; },
        syncResultsFlat: [],
        get visibleSyncFieldKeys() {
            return this._syncSelectedFieldsSnapshot.map(f => f.key);
        },

        async loadMetrics() {
            const root = document.getElementById('creator-page');
            const url = root?.dataset?.metricsUrl;
            if (!url) return;
            try {
                const metrics = await fetchJson(url);
                renderStatsCards('creator-stats', metrics);
            } catch (e) { console.error('loadMetrics error', e); }
        },

        async loadRows() {
            const root = document.getElementById('creator-page');
            const url = root?.dataset?.dataUrl;
            if (!url) return;
            this.loading = true;
            try {
                const params = buildQuery({ ...this.filters, page: this.page, per_page: this.pageSize, sort_field: this.sortField, sort_direction: this.sortDirection });
                const data = await fetchJson(url + '?' + params);
                const pagination = data?.pagination || {};
                this.totalItems = Number(pagination.total || 0);
                this.totalPages = Number(pagination.last_page || 1);
                this.page = Number(pagination.current_page || 1);
                this.pageSize = Number(pagination.per_page || this.pageSize || 10);
                this.rows = Array.isArray(data?.data) ? data.data : [];
                this._updateSortIndicators();
            } catch (e) { console.error('loadRows error', e); }
            finally { this.loading = false; }
        },

        setSort(field) {
            if (this.sortField !== field) { this.sortField = field; this.sortDirection = 'asc'; }
            else if (this.sortDirection === 'asc') { this.sortDirection = 'desc'; }
            else { this.sortField = null; this.sortDirection = 'asc'; }
            this.page = 1;
            this.loadRows();
        },

        collectFilters() {
            const contacts = [];
            document.querySelectorAll('.filter-contact:checked').forEach(cb => contacts.push(cb.value));
            this.filters.contacts = contacts;

            const advantages = [];
            document.querySelectorAll('.filter-advantage:checked').forEach(cb => advantages.push(cb.value));
            this.filters.advantages = advantages;

            const readRange = (minId, maxId) => {
                const minEl = document.getElementById(minId);
                const maxEl = document.getElementById(maxId);
                const min = minEl ? (minEl.value ? Number(minEl.value.replace(/[^0-9]/g, '')) : null) : null;
                const max = maxEl ? (maxEl.value ? Number(maxEl.value.replace(/[^0-9]/g, '')) : null) : null;
                return { min, max };
            };

            const f = readRange('creators-followers-min', 'creators-followers-max');
            this.filters.followers_min = f.min; this.filters.followers_max = f.max;

            const g = readRange('creators-gmv-min', 'creators-gmv-max');
            this.filters.gmv_min = g.min; this.filters.gmv_max = g.max;

            const i = readRange('creators-items-min', 'creators-items-max');
            this.filters.items_min = i.min; this.filters.items_max = i.max;
        },

        resetFilters() {
            this.filters = { keyword: '', contacts: [], advantages: [], followers_min: null, followers_max: null, gmv_min: null, gmv_max: null, items_min: null, items_max: null, classification: '', content: '' };
            document.querySelectorAll('.filter-contact, .filter-advantage').forEach(n => n.checked = false);
            ['creators-followers-min', 'creators-followers-max', 'creators-gmv-min', 'creators-gmv-max', 'creators-items-min', 'creators-items-max'].forEach(id => { const el = document.getElementById(id); if (el) el.value = ''; });
            this.sortField = null; this.sortDirection = 'asc'; this.page = 1; this.loadRows();
        },

        toggleSelectAll() { this.selected = this.selectAll ? this.rows.map(r => r.id) : []; },
        updateSelectAll() { this.selectAll = this.rows.length > 0 && this.selected.length === this.rows.length; },
        clearSelection() { this.selected = []; this.selectAll = false; },

        openAddModal() {
            const form = document.getElementById('addCreatorForm');
            if (form) form.reset();
            modalOpen('addCreatorModal');
        },

        openEditModal(row) {
            this.editingId = row.id;
            const form = document.getElementById('editCreatorForm');
            if (!form) return;
            const fields = ['creator_name', 'tiktok_cid', 'address', 'contact_phone', 'contact_email', 'contact_zalo', 'tiktok_link', 'instagram_link', 'facebook_link', 'followers', 'gmv', 'items', 'average_views', 'advantages', 'audience', 'content', 'notes'];
            const numFields = ['followers', 'gmv', 'items', 'average_views'];
            fields.forEach(f => {
                const el = form.querySelector('[name="' + f + '"]');
                if (el) {
                    const val = row[f] ?? '';
                    el.value = numFields.includes(f) ? window.formatNumberTyping(val) : val;
                }
            });
            modalOpen('editCreatorModal');
        },

        confirmDelete(id) { this.deletingId = id; modalOpen('deleteCreatorConfirmModal'); },

        async executeDeleteCreator() {
            if (!this.deletingId) return;
            const id = this.deletingId;
            this.deletingId = null;
            try {
                await requestJson('/creators/' + id, { method: 'DELETE' });
                showSuccess('Thành công', 'Đã xóa KOL/KOC');
                this.loadRows(); this.loadMetrics();
            } catch (e) { showError('Lỗi', 'Lỗi xóa KOL/KOC: ' + e.message); }
            finally { modalClose('deleteCreatorConfirmModal'); }
        },

        bulkDeleteSelected() {
            if (this.selected.length === 0) { showWarning('Cảnh báo', 'Vui lòng chọn KOC'); return; }
            modalOpen('bulkDeleteCreatorConfirmModal');
        },

        async executeBulkDeleteSelected() {
            const ids = [...this.selected];
            if (ids.length === 0) return;
            try {
                const res = await requestJson('/creators/bulk-delete', {
                    method: 'POST',
                    body: JSON.stringify({ ids: ids }),
                });
                if (res.success) {
                    let message = 'Đã xóa ' + res.deleted + ' KOC';
                    if (res.errors?.length > 0) {
                        message += '. ' + res.errors.length + ' lỗi: ' + res.errors.slice(0, 3).join('; ');
                    }
                    showSuccess('Thành công', message);
                    this.selected = [];
                    this.selectAll = false;
                    this.loadRows();
                    this.loadMetrics();
                }
            } catch (e) {
                showError('Lỗi', 'Lỗi khi xóa KOC: ' + e.message);
            }
        },

        async openBulkAddModal() {
            if (this.selected.length === 0) { showWarning('Cảnh báo', 'Vui lòng chọn KOC'); return; }
            try {
                const root = document.getElementById('creator-page');
                const baseUrl = root?.dataset?.baseUrl || '';
                const url = baseUrl ? baseUrl + '/api/campaigns?limit=500' : '/api/campaigns?limit=500';
                const campaigns = await fetchJson(url);
                if (!Array.isArray(campaigns) || campaigns.length === 0) { showWarning('Cảnh báo', 'Chưa có chiến dịch để thêm KOC vào'); return; }
                this.bulkCampaigns = campaigns;
                this.bulkCampaignId = campaigns[0].id;
                modalOpen('campaignSelectModal');
            } catch (e) { showError('Lỗi', 'Lỗi khi tải danh sách chiến dịch'); }
        },

        async handleBulkAddToCampaign() {
            if (!this.bulkCampaignId) { showWarning('Cảnh báo', 'Vui lòng chọn chiến dịch'); return; }
            const ids = this.selected;
            if (ids.length === 0) { modalClose('campaignSelectModal'); return; }
            const root = document.getElementById('creator-page');
            const baseUrl = root?.dataset?.baseUrl || '';
            const apiBase = baseUrl ? baseUrl + '/api' : '/api';
            try {
                // TỐI ƯU: Gửi 1 request duy nhất thay vì N request
                const res = await fetch(apiBase + '/campaign-kocs/bulk', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content || '' },
                    credentials: 'same-origin',
                    body: JSON.stringify({ campaign_id: this.bulkCampaignId, koc_ids: ids, type: this.bulkBookingType }),
                });
                const data = await res.json();
                const success = data?.success ?? 0;
                const failed = data?.failed ?? 0;
                const alreadyExists = data?.already_exists ?? [];
                const errors = Array.isArray(data?.errors) ? data.errors : [];
                modalClose('campaignSelectModal');

                const getCreatorLabel = (creatorId) => {
                    const row = this.rows.find(r => String(r.id) === String(creatorId));
                    return row?.creator_name ? row.creator_name : ('KOC ' + creatorId);
                };

                const formatList = (items, limit = 5) => {
                    const slice = items.slice(0, limit);
                    const suffix = items.length > limit ? (' và ' + (items.length - limit) + ' KOC khác') : '';
                    return slice.join(', ') + suffix;
                };

                let message = '';
                if (success > 0) message += 'Đã thêm ' + success + ' KOC. ';
                if (alreadyExists.length > 0) {
                    const existedLabels = alreadyExists.map(getCreatorLabel);
                    message += alreadyExists.length + ' KOC đã có trong chiến dịch (bỏ qua): ' + formatList(existedLabels) + '. ';
                }
                if (errors.length > 0) {
                    const errorList = formatList(errors.map(String));
                    message += 'Lỗi khác: ' + errorList + '. ';
                }
                if (failed > alreadyExists.length) message += (failed - alreadyExists.length) + ' KOC bị lỗi.';

                if (failed === 0) showSuccess('Thành công', message || 'Đã thêm ' + success + ' KOC vào chiến dịch');
                else if (success === 0 && alreadyExists.length > 0 && errors.length === 0) {
                    showWarning('Không thể thêm', message.trim());
                }
                else showWarning('Cảnh báo', message.trim());
                this.loadRows(); this.loadMetrics();
            } catch (e) {
                modalClose('campaignSelectModal');
                showError('Lỗi', 'Lỗi khi thêm KOC vào chiến dịch: ' + e.message);
            }
        },

        pageSizeChange() { this.page = 1; this.loadRows(); },
        goToPage(p) { this.page = Math.max(1, Math.min(p, this.totalPages)); this.loadRows(); },
        prevPage() { if (this.page > 1) { this.page--; this.loadRows(); } },
        nextPage() { if (this.page < this.totalPages) { this.page++; this.loadRows(); } },

        _parseNumericFields(data) {
            ['followers', 'gmv', 'items', 'average_views'].forEach(f => {
                if (data[f] !== undefined && data[f] !== '') {
                    const cleaned = cleanNumberForSubmit(data[f]);
                    data[f] = cleaned !== null ? cleaned : data[f];
                }
            });
        },

        submitAddCreator: window.withSubmitGuard('creator_add', async function (e) {
            e.preventDefault();
            const form = document.getElementById('addCreatorForm');
            if (!form) return;
            const data = Object.fromEntries(new FormData(form).entries());
            this._parseNumericFields(data);
            try {
                const root = document.getElementById('creator-page');
                const baseUrl = root?.dataset?.baseUrl || '';
                const url = baseUrl ? baseUrl + '/creators' : '/creators';
                await requestJson(url, { method: 'POST', body: JSON.stringify(data) });
                showSuccess('Thành công', 'Đã thêm KOL/KOC mới');
                modalClose('addCreatorModal');
                form.reset();
                this.loadRows(); this.loadMetrics();
            } catch (e) {
                if (e.errors && e.errors.creator_name) {
                    showError('Lỗi', e.errors.creator_name[0] || 'Tên KOL/Creator đã tồn tại');
                } else {
                    showError('Lỗi', e.message);
                }
            }
        }),

        submitEditCreator: window.withSubmitGuard('creator_edit', async function (e) {
            e.preventDefault();
            if (!this.editingId) return;
            const form = document.getElementById('editCreatorForm');
            if (!form) return;
            const data = Object.fromEntries(new FormData(form).entries());
            this._parseNumericFields(data);
            try {
                const root = document.getElementById('creator-page');
                const baseUrl = root?.dataset?.baseUrl || '';
                const url = baseUrl ? baseUrl + '/creators/' + this.editingId : '/creators/' + this.editingId;
                await requestJson(url, { method: 'PUT', body: JSON.stringify(data) });
                showSuccess('Thành công', 'Đã cập nhật KOL/KOC');
                modalClose('editCreatorModal');
                form.reset();
                this.editingId = null;
                this.loadRows(); this.loadMetrics();
            } catch (e) {
                if (e.errors && e.errors.creator_name) {
                    showError('Lỗi', e.errors.creator_name[0] || 'Tên KOL/Creator đã tồn tại');
                } else {
                    showError('Lỗi', e.message);
                }
            }
        }),

        async handleImportCSV(e) {
            const file = e.target.files?.[0];
            if (!file) return;
            const root = document.getElementById('creator-page');
            const form = new FormData();
            form.append('file', file);
            form.append('_token', document.querySelector('meta[name="csrf-token"]')?.content || '');
            try {
                const baseUrl = root?.dataset?.baseUrl || '';
                const url = baseUrl ? baseUrl + '/creators/import-csv' : '/creators/import-csv';
                const res = await fetch(url, { method: 'POST', body: form, credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } });
                const data = await res.json().catch(() => ({}));

                const inserted = data.inserted ?? 0;
                const errList = Array.isArray(data.errors) ? data.errors : [];
                let message = 'Đã import ' + inserted + ' KOC';
                if (errList.length > 0) {
                    message += '. ' + errList.length + ' lỗi: ' + errList.slice(0, 5).join('; ');
                    if (errList.length > 5) message += '...';
                }
                if (data.error) {
                    showError('Lỗi', data.error);
                } else if (inserted > 0 || errList.length > 0) {
                    showSuccess('Thành công', message);
                } else {
                    showWarning('Hoàn tất', message + '. Kiểm tra lại tiêu đề cột (cần có "Tên KOC" hoặc "creator_name").');
                }
                this.loadRows();
                this.loadMetrics();
            } catch (e) { showError('Lỗi', 'Lỗi khi import: ' + e.message); }
            finally { e.target.value = ''; }
        },

        async handleBulkEditCSV(e) {
            const file = e.target.files?.[0];
            if (!file) return;
            const root = document.getElementById('creator-page');
            const form = new FormData();
            form.append('file', file);
            form.append('_token', document.querySelector('meta[name="csrf-token"]')?.content || '');
            try {
                const baseUrl = root?.dataset?.baseUrl || '';
                const url = baseUrl ? baseUrl + '/creators/bulk-update' : '/creators/bulk-update';
                const res = await fetch(url, { method: 'POST', body: form, credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } });
                const data = await res.json().catch(() => ({}));

                if (data.error) {
                    showError('Lỗi', data.error);
                } else {
                    const updated = data.updated || 0;
                    const notFound = Array.isArray(data.not_found) ? data.not_found : [];
                    const errors = Array.isArray(data.errors) ? data.errors : [];
                    let message = 'Đã cập nhật ' + updated + ' KOC';
                    if (notFound.length > 0) {
                        message += '. Không tìm thấy: ' + notFound.slice(0, 5).join(', ');
                        if (notFound.length > 5) message += '...';
                    }
                    if (errors.length > 0) {
                        message += '. Lỗi: ' + errors.slice(0, 5).join('; ');
                        if (errors.length > 5) message += '...';
                    }
                    if (updated > 0) {
                        showSuccess('Thành công', message);
                    } else {
                        showWarning('Cảnh báo', message);
                    }
                    this.loadRows();
                    this.loadMetrics();
                }
            } catch (e) { showError('Lỗi', 'Lỗi khi cập nhật: ' + e.message); }
            finally { e.target.value = ''; }
        },

        shuffleRows() {
            if (!this.rows || this.rows.length === 0) { showWarning('Cảnh báo', 'Không có dữ liệu để xáo trộn'); return; }
            for (let i = this.rows.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1));[this.rows[i], this.rows[j]] = [this.rows[j], this.rows[i]]; }
            this.page = 1;
        },

        async exportCSV() {
            if (!this.canExport) { showError('Lỗi', 'Bạn không có quyền xuất file. Chỉ admin/owner mới được phép.'); return; }
            if (!this.rows || this.rows.length === 0) { showWarning('Cảnh báo', 'Không có dữ liệu để xuất'); return; }
            const headers = ['Tên KOL', 'TikTok', 'CID TikTok', 'Instagram', 'Facebook', 'SĐT', 'Email', 'Zalo', 'Followers', 'GMV', 'Số món', 'View TB', 'Lợi thế', 'Phân loại', 'Content', 'Tệp KH', 'Địa chỉ', 'Ghi chú', 'Chiến dịch'];
            const rows = this.rows.map(r => [r.creator_name || '', r.tiktok_link || '', r.tiktok_cid || '', r.instagram_link || '', r.facebook_link || '', r.contact_phone || '', r.contact_email || '', r.contact_zalo || '', r.followers || 0, r.gmv || 0, r.items || 0, r.average_views || 0, r.advantages || '', r.classification || '', r.content || '', r.audience || '', r.address || '', r.notes || '', r.campaigns_count || 0]);
            try { await downloadXlsx('KOC_' + new Date().toISOString().split('T')[0], headers, rows); }
            catch (e) { showError('Lỗi', 'Không thể xuất file: ' + e.message); }
        },

        async exportSelectedCSV() {
            if (!this.canExport) { showError('Lỗi', 'Bạn không có quyền xuất file. Chỉ admin/owner mới được phép.'); return; }
            const ids = this.selected;
            const filtered = this.rows.filter(r => ids.includes(String(r.id)));
            if (!filtered || filtered.length === 0) { showError('Lỗi', 'Không tìm thấy dữ liệu đã chọn'); return; }
            const headers = ['Tên KOL', 'TikTok', 'CID TikTok', 'Instagram', 'Facebook', 'SĐT', 'Email', 'Zalo', 'Followers', 'GMV', 'Số món', 'View TB', 'Lợi thế', 'Phân loại', 'Content', 'Tệp KH', 'Địa chỉ', 'Ghi chú', 'Chiến dịch'];
            const rows = filtered.map(r => [r.creator_name || '', r.tiktok_link || '', r.tiktok_cid || '', r.instagram_link || '', r.facebook_link || '', r.contact_phone || '', r.contact_email || '', r.contact_zalo || '', r.followers || 0, r.gmv || 0, r.items || 0, r.average_views || 0, r.advantages || '', r.classification || '', r.content || '', r.audience || '', r.address || '', r.notes || '', r.campaigns_count || 0]);
            try { await downloadXlsx('KOC_selected_' + new Date().toISOString().split('T')[0], headers, rows); }
            catch (e) { showError('Lỗi', 'Không thể xuất file: ' + e.message); }
        },

        downloadTemplate() {
            const headers = ['Tên KOC', 'TikTok', 'Instagram', 'Facebook', 'SĐT', 'Email', 'Zalo', 'CID TikTok', 'Followers', 'GMV', 'Số món bán ra', 'Lượt xem TB', 'Lợi thế', 'Nội dung', 'Tệp KH', 'Địa chỉ', 'Ghi chú'];
            const rows = [['KOC Nguyễn Văn A', 'https://www.tiktok.com/@kocnguyena', 'https://www.instagram.com/kocnguyena/', 'https://www.facebook.com/kocnguyena', '0901234567', 'nguyena@email.com', '0901234567', '123456789', 50000, 1000000, 150, 50000, 'Video;Livestream', 'Fashion & Style', 'Nữ 18-30;Mẹ bỉm', 'Hà Nội', 'KOC chuyên về fashion']];
            downloadXlsx('koc_import_template', headers, rows).catch(e => showError('Lỗi', 'Không thể tải template: ' + e.message));
        },

        formatNumber(v) { return formatNumber(v); },
        formatCurrency(v) { return formatCurrency(v); },

        _bindAddForm() {
            if (this._addFormBound) return;
            const form = document.getElementById('addCreatorForm');
            if (form) { form.addEventListener('submit', (e) => this.submitAddCreator(e)); this._addFormBound = true; }
        },

        _bindEditForm() {
            if (this._editFormBound) return;
            const form = document.getElementById('editCreatorForm');
            if (form) { form.addEventListener('submit', (e) => this.submitEditCreator(e)); this._editFormBound = true; }
        },

        /**
         * Thêm log debug hiển thị trong modal tiến trình
         */
        _syncDebug(label, data = null) {
            const time = formatTime(new Date());
            let msg = `[${time}] ${label}`;
            if (data !== null) {
                try {
                    msg += `\n${JSON.stringify(data, null, 2)}`;
                } catch (e) {
                    msg += `\n${String(data)}`;
                }
            }
            this.syncDebugLogs.push(msg);
            if (this.syncDebugLogs.length > 200) {
                this.syncDebugLogs.splice(0, 50);
            }
            console.log('[Sync Debug]', label, data);
        },

        /**
         * Mở modal chọn trường thông tin cần đồng bộ từ TikTok
         */
        openSyncModal() {
            // Kiểm tra Extension đã cài chưa
            if (!this.extensionReady && !document.getElementById('kocbooking-extension-installed')) {
                showWarning(
                    '⚙️ Cần cài Extension',
                    'Tính năng này yêu cầu cài tiện ích mở rộng Chrome. ' +
                    'Tải tại: <b>Chrome → Extensions → Load Unpacked → chọn thư mục kocbooking-extension</b>'
                );
                return;
            }
            this.extensionReady = true;
            this.syncAllKocs = true;
            this.syncSelectAll = this.syncFieldsList.every(f => f.checked);
            this._loadSyncKocCount();
            modalOpen('syncFieldsModal');
        },

        /**
         * Lấy tổng số KOC để giới hạn phạm vi đồng bộ
         */
        async _loadSyncKocCount() {
            try {
                const root = document.getElementById('creator-page');
                const url = root?.dataset?.dataUrl;
                if (!url) return;
                const res = await fetch(url + '?per_page=1', {
                    headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
                    credentials: 'same-origin'
                });
                const json = await res.json();
                this.totalKocCount = json?.pagination?.total || 0;
                if (this.syncAllKocs && this.totalKocCount > 0) {
                    this.syncFromKoc = 1;
                    this.syncToKoc = this.totalKocCount;
                }
            } catch (e) {
                console.warn('[Sync] Không thể tải tổng số KOC:', e.message);
                this.totalKocCount = 0;
            }
        },

        /**
         * Bắt đầu đồng bộ qua Extension (không dùng PHP backend nữa)
         * Thu thập dữ liệu vào syncResults, không cập nhật DB ngay
         */
        async submitSyncTikTok() {
            modalClose('syncFieldsModal');
            if (this.syncing) return;

            this.syncDebugLogs = [];
            this.syncResults = [];
            this.syncResultsFlat = [];

            const selectedFields = this.syncFieldsList.filter(f => f.checked).map(f => f.key);
            if (selectedFields.length === 0) {
                showWarning('Cảnh báo', 'Vui lòng chọn ít nhất một trường thông tin để đồng bộ.');
                return;
            }

            // Lưu snapshot các field đã chọn để dùng trong review modal
            // Expand 'contact' → contact_phone, contact_zalo, contact_email
            this._syncSelectedFieldsSnapshot = [];
            for (const f of this.syncFieldsList) {
                if (!f.checked) continue;
                if (f.key === 'contact') {
                    this._syncSelectedFieldsSnapshot.push({ key: 'contact_phone', label: 'Số điện thoại' });
                    this._syncSelectedFieldsSnapshot.push({ key: 'contact_zalo', label: 'Zalo' });
                    this._syncSelectedFieldsSnapshot.push({ key: 'contact_email', label: 'Email' });
                } else {
                    this._syncSelectedFieldsSnapshot.push({ key: f.key, label: f.label });
                }
            }

            // Kiểm tra phạm vi hợp lệ
            if (this.totalKocCount > 0) {
                if (this.syncFromKoc < 1) this.syncFromKoc = 1;
                if (this.syncFromKoc > this.totalKocCount) {
                    showWarning('Phạm vi không hợp lệ', `KOC bắt đầu (${this.syncFromKoc}) vượt quá tổng số KOC (${this.totalKocCount}).`);
                    this.syncing = false;
                    return;
                }
                if (this.syncToKoc > this.totalKocCount) {
                    this.syncToKoc = this.totalKocCount;
                }
            }

            // 1. Kiểm tra đăng nhập TikTok qua Extension
            this.syncing = true;
            this.syncAborted = false;
            this.showSyncProgress = true;
            this.syncProgressFinished = false;
            this.syncProgressMessage = 'Đang kiểm tra đăng nhập TikTok...';
            this.syncProgressCurrent = 0;
            this.syncProgressTotal = 0;
            this.syncProgressPercent = 0;
            this.syncStats = { updated: 0, notFound: 0, missingCid: 0, errors: 0 };

            this._syncDebug('Bắt đầu đồng bộ', { selectedFields, syncFromKoc: this.syncFromKoc, syncToKoc: this.syncToKoc });

            // Kiểm tra extension đã cài chưa
            const extInstalled = document.getElementById('kocbooking-extension-installed');
            this._syncDebug('Kiểm tra extension marker', { found: !!extInstalled });
            if (!extInstalled) {
                this.syncProgressMessage = '⛔ Extension chưa được cài đặt. Vui lòng cài extension Chrome trước.';
                this.syncProgressFinished = true;
                this.syncing = false;
                this._syncDebug('LỖI: Không tìm thấy extension marker #kocbooking-extension-installed');
                return;
            }

            this._syncDebug('Gửi SYNC_ONE_CREATOR đến extension (kiểm tra đăng nhập luôn)...');

            // 1b. Tạo sync session token để bảo vệ dữ liệu
            this.syncProgressMessage = 'Đang khởi tạo phiên đồng bộ...';
            this.syncSessionToken = '';
            try {
                const csrfMeta = document.querySelector('meta[name="csrf-token"]');
                const sessionRes = await fetch('/api/sync/start-session', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': csrfMeta?.content ?? '',
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                    credentials: 'same-origin',
                });
                const sessionJson = await sessionRes.json();
                if (sessionJson?.success && sessionJson?.session_token) {
                    this.syncSessionToken = sessionJson.session_token;
                    this._syncDebug('Phiên đồng bộ đã tạo', { token: sessionJson.session_token });
                } else {
                    this._syncDebug('⚠️ Không thể tạo session token, tiếp tục không có bảo vệ');
                }
            } catch (e) {
                this._syncDebug('⚠️ Lỗi tạo sync session:', { error: e.message });
            }

            // 2. Lấy danh sách KOC từ API
            this.syncProgressMessage = 'Đang tải danh sách KOC...';
            this._syncDebug('Fetch danh sách KOC từ API...');
            let creators = [];
            try {
                const root = document.getElementById('creator-page');
                const baseUrl = root?.dataset?.baseUrl || '';
                const res = await fetch(baseUrl + '/api/kocs?limit=9999', {
                    headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
                    credentials: 'same-origin'
                });
                const json = await res.json();
                creators = Array.isArray(json?.data) ? json.data : (Array.isArray(json) ? json : []);
                this._syncDebug('Kết quả API /api/kocs', { total: creators.length, firstFew: creators.slice(0, 3) });
            } catch (e) {
                this._syncDebug('LỖI fetch /api/kocs', { error: e.message });
                this.syncProgressMessage = 'Lỗi khi tải danh KOC: ' + e.message;
                this.syncProgressFinished = true;
                this.syncing = false;
                return;
            }

            if (creators.length === 0) {
                this.syncProgressMessage = '⛔ Không có KOC nào trong tổ chức.';
                this.syncProgressFinished = true;
                this.syncing = false;
                return;
            }

            // Áp dụng phạm vi KOC (from → to)
            const fromIdx = Math.max(0, (this.syncFromKoc || 1) - 1);
            const toIdx = Math.min(this.syncToKoc || this.totalKocCount, creators.length);
            const processList = creators.slice(fromIdx, toIdx);

            this.syncProgressTotal = processList.length;
            this._syncDebug(`Phạm vi KOC: từ #${fromIdx + 1} đến #${toIdx} (tổng: ${processList.length}/${creators.length})`);

            if (processList.length === 0) {
                this.syncProgressMessage = '⛔ Không có KOC nào trong phạm vi đã chọn.';
                this.syncProgressFinished = true;
                this.syncing = false;
                return;
            }

            // 3. Lặp qua từng KOC: Extension scrape → thu thập vào syncResults
            for (let i = 0; i < processList.length; i++) {
                if (this.syncAborted) break;

                const creator = processList[i];
                this.syncProgressCurrent = i + 1;
                this.syncProgressPercent = Math.round(((i + 1) / processList.length) * 100);
                this.syncProgressMessage = `[${i + 1}/${processList.length}] Đang xử lý: ${creator.creator_name}`;

                this._syncDebug(`▶️ Bắt đầu xử lý KOC: "${creator.creator_name}" (id: ${creator.id})`);

                const resultItem = {
                    creatorId: creator.id,
                    creator_name: creator.creator_name,
                    tiktok_cid: creator.tiktok_cid,
                    data: {},
                    oldData: {
                        followers: creator.followers ?? '',
                        gmv: creator.gmv ?? '',
                        items: creator.items ?? '',
                        average_views: creator.average_views ?? '',
                        advantages: creator.advantages ?? '',
                        contact_phone: creator.contact_phone ?? '',
                        contact_zalo: creator.contact_zalo ?? '',
                        contact_email: creator.contact_email ?? '',
                    },
                    status: '⏳ Đang xử lý'
                };

                // Bỏ qua nếu KOC chưa có tiktok_cid
                if (!creator.tiktok_cid) {
                    this._syncDebug(`✖️ THIẾU tiktok_cid cho "${creator.creator_name}" — bỏ qua`);
                    resultItem.status = '❌ Thiếu CID';
                    this.syncStats.missingCid++;
                    this.syncResults.push(resultItem); this._pushSyncResultFlat(resultItem);
                    continue;
                }

                try {
                    this._syncDebug(`Gửi SYNC_ONE_CREATOR đến extension...`, selectedFields);
                    const result = await this._extensionRequest({
                        action: 'SYNC_ONE_CREATOR',
                        creatorName: creator.creator_name,
                        creatorCid: creator.tiktok_cid,
                        fields: selectedFields
                    });

                    this._syncDebug(`Kết quả từ extension cho "${creator.creator_name}"`, result);

                    if (!result || !result.success) {
                        const reason = result?.error || 'Không có phản hồi từ extension';
                        this._syncDebug(`✖️ THẤT BẠI: ${reason}`);
                        resultItem.status = '⚠️ Lỗi: ' + reason;
                        if (reason === 'NOT_FOUND') {
                            this.syncStats.notFound++;
                        } else if (reason === 'LOGIN_REQUIRED') {
                            this.syncProgressMessage = '⛔ Chưa đăng nhập TikTok Affiliate. Vui lòng đăng nhập vào tab TikTok rồi thử lại.';
                            this.syncAborted = true;
                            showWarning('Chưa đăng nhập', 'Vui lòng đăng nhập TikTok Affiliate Creator Center trước.');
                            break;
                        } else {
                            this.syncStats.errors++;
                        }
                        this.syncResults.push(resultItem); this._pushSyncResultFlat(resultItem);
                        continue;
                    }

                    // Lọc chỉ các trường được chọn
                    const rawData = result.data || {};
                    this._syncDebug(`Dữ liệu scrape được`, rawData);

                    const filteredData = {};
                    for (const field of selectedFields) {
                        if (field === 'contact') {
                            if (rawData['contact_phone'] !== undefined && rawData['contact_phone'] !== null && rawData['contact_phone'] !== '') filteredData['contact_phone'] = rawData['contact_phone'];
                            if (rawData['contact_zalo'] !== undefined && rawData['contact_zalo'] !== null && rawData['contact_zalo'] !== '') filteredData['contact_zalo'] = rawData['contact_zalo'];
                            if (rawData['contact_email'] !== undefined && rawData['contact_email'] !== null && rawData['contact_email'] !== '') filteredData['contact_email'] = rawData['contact_email'];
                        } else if (rawData[field] !== undefined && rawData[field] !== null && rawData[field] !== '') {
                            filteredData[field] = rawData[field];
                        }
                    }

                    this._syncDebug(`Dữ liệu sau khi lọc field`, { selectedFields, filteredData });

                    resultItem.data = filteredData;
                    resultItem.status = Object.keys(filteredData).length > 0
                        ? '✅ Có dữ liệu'
                        : '⚠️ Không có dữ liệu';
                    this.syncStats.updated++;

                    this.syncResults.push(resultItem); this._pushSyncResultFlat(resultItem);
                } catch (e) {
                    this._syncDebug(`💥 EXCEPTION khi xử lý "${creator.creator_name}"`, { error: e.message, stack: e.stack });
                    console.error('[Sync] Lỗi KOC', creator.creator_name, e);
                    resultItem.status = '⚠️ Lỗi: ' + e.message;
                    this.syncStats.errors++;
                    this.syncResults.push(resultItem); this._pushSyncResultFlat(resultItem);
                }
            }

            // 4. Đóng tab TikTok sau khi xong
            this._syncDebug('Đóng tab TikTok...');
            this._extensionRequest({ action: 'CLOSE_TIKTOK_TAB' }).catch(() => { });

            // 5. Hiển thị kết quả trong progress modal (không chuyển sang review modal riêng)
            const { updated, notFound, missingCid, errors } = this.syncStats;
            const summary = `✅ Đã đồng bộ: ${this.syncResults.length} | ❌ Không thấy: ${notFound} | ⚠️ Thiếu CID: ${missingCid} | ⚠️ Lỗi: ${errors}`;
            this.syncProgressMessage = this.syncAborted
                ? `Đã dừng. ${summary}`
                : `Hoàn tất thu thập! ${summary}`;
            this.syncProgressPercent = 100;
            this.syncProgressFinished = true;
            this.syncing = false;
            const now = new Date();
            this.lastSyncAt = formatDateTime(now);
            this.lastSyncFrom = this.syncFromKoc;
            this.lastSyncTo = this.syncToKoc;
            this._syncDebug('Kết thúc đồng bộ', { stats: this.syncStats, lastSyncAt: this.lastSyncAt, from: this.lastSyncFrom, to: this.lastSyncTo });
            fetch('/api/sync/log-sync', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content ?? '' },
                body: JSON.stringify({ from: this.lastSyncFrom, to: this.lastSyncTo, updated: this.syncResults.length }),
            }).catch(() => { });

            if (this.syncResults.length === 0) {
                showWarning('Không có dữ liệu', 'Không có KOC nào được đồng bộ. Vui lòng kiểm tra lại.');
            }
        },

        /**
         * Cập nhật toàn bộ dữ liệu đã duyệt lên database
         */
        async confirmSyncUpdates() {
            if (this.syncReviewUpdating) return;
            if (this.syncResultsFlat.length === 0) {
                showWarning('Cảnh báo', 'Không có dữ liệu để cập nhật.');
                return;
            }

            this.syncReviewUpdating = true;
            this.syncReviewUpdatedCount = 0;

            let successCount = 0;
            let errorCount = 0;

            const root = document.getElementById('creator-page');
            const baseUrl = root?.dataset?.baseUrl || '';
            const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
            const selectedKeys = this._syncSelectedFieldsSnapshot.map(f => f.key);

            for (let i = 0; i < this.syncResultsFlat.length; i++) {
                const flat = this.syncResultsFlat[i];

                const numericKeys = ['followers', 'gmv', 'items', 'average_views'];
                const stringKeys = ['contact_phone', 'contact_zalo', 'contact_email'];
                const payload = {};
                for (const key of selectedKeys) {
                    const value = flat[key];
                    if (value !== undefined && value !== null && value !== '') {
                        if (numericKeys.includes(key) && window.cleanNumberForSubmit) {
                            payload[key] = window.cleanNumberForSubmit(String(value));
                        } else if (stringKeys.includes(key)) {
                            payload[key] = String(value);
                        } else {
                            payload[key] = value;
                        }
                    }
                }

                if (Object.keys(payload).length === 0) {
                    flat.status = '⏭️ Bỏ qua (không có dữ liệu)';
                    this.syncReviewUpdatedCount++;
                    continue;
                }

                try {
                    const headers = {
                        'Content-Type': 'application/json',
                        'X-Requested-With': 'XMLHttpRequest',
                        'X-CSRF-TOKEN': csrfToken,
                        'X-Sync-Source': 'sync_tiktok',
                    };
                    if (this.syncSessionToken) {
                        headers['X-Sync-Session-Token'] = this.syncSessionToken;
                    }
                    const putRes = await fetch(baseUrl + '/creators/' + flat.creatorId, {
                        method: 'PUT',
                        headers: headers,
                        credentials: 'same-origin',
                        body: JSON.stringify(payload)
                    });

                    if (putRes.ok) {
                        flat.status = '✅ Đã cập nhật';
                        successCount++;
                    } else {
                        const errBody = await putRes.json().catch(() => ({}));
                        const errMsg = errBody?.message || errBody?.error || `HTTP ${putRes.status}`;
                        flat.status = '❌ Lỗi: ' + errMsg;
                        errorCount++;
                    }
                } catch (e) {
                    flat.status = '❌ Lỗi: ' + e.message;
                    errorCount++;
                }

                this.syncReviewUpdatedCount = i + 1;
            }

            this.syncReviewUpdating = false;

            let msg = `✅ Đã cập nhật: ${successCount}`;
            if (errorCount > 0) msg += ` | ❌ Lỗi: ${errorCount}`;
            showSuccess('Hoàn tất cập nhật DB', msg);

            this.loadRows();
            this.loadMetrics();

            this._closeSyncSession();
        },

        /**
         * Tải file Excel kết quả đồng bộ - không đóng modal để user còn cập nhật DB
         */
        async downloadSyncResults() {
            if (this.syncResultsFlat.length === 0) {
                showWarning('Cảnh báo', 'Không có dữ liệu để xuất.');
                return;
            }

            const fields = this._syncSelectedFieldsSnapshot;
            const headers = ['Tên KOC', ...fields.map(f => f.label)];
            const rows = this.syncResultsFlat.map(item => {
                return [
                    item.creator_name,
                    ...fields.map(f => {
                        const val = item[f.key];
                        return val !== undefined && val !== null ? String(val) : '';
                    })
                ];
            });

            try {
                await downloadXlsx('ket_qua_dong_bo_tiktok_' + new Date().toISOString().split('T')[0], headers, rows);
                showSuccess('Thành công', 'Đã tải file kết quả đồng bộ.');
            } catch (e) {
                showError('Lỗi', 'Không thể tải file: ' + e.message);
            }
        },

        /**
         * Hủy bỏ kết quả đồng bộ, đóng review modal
         */
        cancelSyncResults() {
            if (this.syncReviewUpdating) return;
            this.showSyncProgress = false;
            this.syncResults = [];
            this.syncResultsFlat = [];
            this._syncSelectedFieldsSnapshot = [];
            this.syncDebugLogs = [];
            this._closeSyncSession();
        },

        _closeSyncSession() {
            if (!this.syncSessionToken) return;
            const csrfMeta = document.querySelector('meta[name="csrf-token"]');
            fetch('/api/sync/end-session', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': csrfMeta?.content ?? '',
                },
                body: JSON.stringify({ session_token: this.syncSessionToken }),
            }).catch(() => { });
            this.syncSessionToken = '';
        },

        /**
         * Dừng đồng bộ giữa chừng
         */
        abortSync() {
            this.syncAborted = true;
            this.syncProgressMessage = 'Đang dừng...';
        },

        closeSyncProgress() {
            this.showSyncProgress = false;
        },

        _pushSyncResultFlat(item) {
            const idx = this.syncResultsFlat.length;
            this.syncResultsFlat.push({
                _index: idx + 1,
                creatorId: item.creatorId,
                creator_name: item.creator_name,
                // New values from sync (editable)
                followers: item.data?.followers ?? '',
                gmv: item.data?.gmv ?? '',
                items: item.data?.items ?? '',
                average_views: item.data?.average_views ?? '',
                advantages: item.data?.advantages ?? '',
                contact_phone: item.data?.contact_phone ?? '',
                contact_zalo: item.data?.contact_zalo ?? '',
                contact_email: item.data?.contact_email ?? '',
                // Old values from DB (readonly comparison)
                followers_old: item.oldData?.followers ?? '',
                gmv_old: item.oldData?.gmv ?? '',
                items_old: item.oldData?.items ?? '',
                average_views_old: item.oldData?.average_views ?? '',
                advantages_old: item.oldData?.advantages ?? '',
                contact_phone_old: item.oldData?.contact_phone ?? '',
                contact_zalo_old: item.oldData?.contact_zalo ?? '',
                contact_email_old: item.oldData?.contact_email ?? '',
                status: item.status,
            });
        },

        syncStatusHtml(status) {
            if (!status) return '<span>-</span>';
            if (status.includes('✅')) return `<span style="color:#16a34a;font-weight:600;">${status}</span>`;
            if (status.includes('❌')) return `<span style="color:#dc2626;font-weight:600;">${status}</span>`;
            if (status.includes('⚠️')) return `<span style="color:#ca8a04;font-weight:600;">${status}</span>`;
            if (status.includes('⏳')) return `<span style="color:#2563eb;">${status}</span>`;
            if (status.includes('⏭️')) return `<span style="color:#6b7280;">${status}</span>`;
            return `<span>${status}</span>`;
        },

        /**
         * Gửi yêu cầu đến Chrome Extension thông qua CustomEvent bridge
         */
        _extensionRequest(payload) {
            const action = payload.action;
            const reqId = Date.now() + '_' + Math.random().toString(36).slice(2, 6);
            this._syncDebug(`_extensionRequest[${reqId}] Gửi:`, payload);

            return new Promise((resolve) => {
                const timeout = setTimeout(() => {
                    window.removeEventListener('KOC_SYNC_RESPONSE', handler);
                    const errMsg = `Extension timeout (60s) - không nhận được phản hồi cho action "${action}"`;
                    this._syncDebug(`_extensionRequest[${reqId}] ⏰ TIMEOUT: ${errMsg}`);
                    resolve({ success: false, error: errMsg });
                }, 60000);

                const handler = (event) => {
                    const detail = event.detail;
                    if (detail?.action === action) {
                        clearTimeout(timeout);
                        window.removeEventListener('KOC_SYNC_RESPONSE', handler);
                        this._syncDebug(`_extensionRequest[${reqId}] Nhận response:`, detail);
                        resolve(detail);
                    }
                };

                window.addEventListener('KOC_SYNC_RESPONSE', handler);
                window.dispatchEvent(new CustomEvent('KOC_SYNC_REQUEST', { detail: payload }));

                // Log đã dispatch
                this._syncDebug(`_extensionRequest[${reqId}] Đã dispatch KOC_SYNC_REQUEST, chờ response...`);
            });
        },

        _updateSortIndicators() {
            document.querySelectorAll('.sortable-header').forEach(h => h.classList.remove('sort-asc', 'sort-desc'));
            if (!this.sortField) return;
            const active = document.querySelector('.sortable-header[data-sort-field="' + this.sortField + '"]');
            if (active) active.classList.add(this.sortDirection === 'asc' ? 'sort-asc' : 'sort-desc');
        },


    }));
}
