import { defineStore } from 'pinia';
import { ref, reactive, watch } from 'vue';
import axios from 'axios';

export interface Project {
    id: number;
    name: string;
    signal_type: 'site' | 'call' | 'sms';
    signal_identifier?: string | null;
    sms_senders?: string[] | null;
    sms_keyword?: string | null;
    daily_limit_target: number;
    delivered_today: number;
    delivered_in_month?: number;
    is_active: boolean;
    region_mask?: number;
    region_mode?: string;
    regions?: number[]; // Plan 6 — subject codes 1..89; пустой массив = вся РФ
    delivery_days_mask?: number;
    sync_status: 'ok' | 'pending' | 'failed';
    last_synced_at?: string | null;
    // H (балансовый блок): проект приостановлен из-за нехватки баланса (preflight_blocked_at).
    balance_blocked?: boolean;
    // Блокировка смены источника (спека 2026-06-22-project-source-edit-lock-ux).
    source_locked?: boolean;
    source_unlock_at?: string | null;
    source_unlock_projected?: boolean;
    // Эпик 6.3: единый текст правила смены источника (из ProjectRuleMessages на бэкенде).
    source_change_message?: string | null;
}

export const useProjectsStore = defineStore('projects', () => {
    const items = ref<Project[]>([]);
    const total = ref(0);
    // #6/#7: per_page 20/50/100/200, sort ('-delivered_today' default), region (subject code 1..89), delivery_day (0..6).
    const filters = reactive<{
        signal_type: string;
        status: string;
        search: string;
        page: number;
        per_page: number;
        sort: string;
        region: number | null;
        delivery_day: number | null;
    }>({
        signal_type: '',
        status: '',
        search: '',
        page: 1,
        per_page: 20,
        sort: '-delivered_today',
        region: null,
        delivery_day: null,
    });
    const selectedIds = ref<Set<number>>(new Set());
    const pendingIds = ref<Set<number>>(new Set());
    const loading = ref(false);
    const selectAllByFilter = ref<boolean>(false);

    // Closure state for polling — kept outside returned store surface.
    let pollTimeout: ReturnType<typeof setTimeout> | null = null;
    let currentDelay = 5000;
    const DELAY_OK = 5000;
    const DELAY_MAX = 30000;

    async function fetch() {
        loading.value = true;
        try {
            const params: Record<string, unknown> = { page: filters.page, per_page: filters.per_page };
            if (filters.signal_type) params.signal_type = filters.signal_type;
            if (filters.status) params.status = filters.status;
            if (filters.search) params.search = filters.search;
            if (filters.sort) params.sort = filters.sort;
            if (filters.region !== null) params.region = filters.region;
            if (filters.delivery_day !== null) params.delivery_day = filters.delivery_day;
            const { data } = await axios.get('/api/projects', { params });
            items.value = data.data;
            total.value = data.meta.total;
        } finally {
            loading.value = false;
        }
    }

    async function create(payload: Partial<Project>) {
        const { data } = await axios.post('/api/projects', payload);
        pendingIds.value.add(data.data.id);
        await fetch();
        return data.data;
    }

    async function update(id: number, payload: Partial<Project>) {
        const { data } = await axios.patch(`/api/projects/${id}`, payload);
        await fetch();
        return data.data;
    }

    async function del(id: number) {
        await axios.delete(`/api/projects/${id}`);
        await fetch();
    }

    async function syncNow(id: number) {
        await axios.post(`/api/projects/${id}/sync`);
        pendingIds.value.add(id);
        await fetch();
    }

    async function toggleActive(project: Project) {
        await axios.patch(`/api/projects/${project.id}/toggle-active`, { is_active: !project.is_active });
        await fetch();
    }

    function toggleSelect(id: number) {
        selectAllByFilter.value = false; // user opted into manual mode
        if (selectedIds.value.has(id)) {
            selectedIds.value.delete(id);
        } else {
            selectedIds.value.add(id);
        }
    }

    function clearSelection() {
        selectedIds.value.clear();
    }

    async function bulkAction(action: 'pause' | 'resume' | 'delete') {
        const ids = Array.from(selectedIds.value);
        if (!ids.length) return;
        await axios.post('/api/projects/bulk', { action, ids });
        clearSelection();
        await fetch();
    }

    interface BulkPayload {
        action: 'pause' | 'resume' | 'delete' | 'update_regions' | 'update_days' | 'update_limit';
        add?: number;
        remove?: number;
        // Plan 6.5 — update_regions оперирует кодами субъектов (1..89), не bitmask ФО.
        add_regions?: number[];
        remove_regions?: number[];
        delta?: number;
        replace?: number;
    }

    interface BulkResponse {
        updated: number;
        skipped: Array<{ id: number; reason: string }>;
        warnings: string[];
    }

    async function bulkUpdate(payload: BulkPayload): Promise<BulkResponse> {
        const body: Record<string, unknown> = { ...payload };

        if (selectAllByFilter.value) {
            const f: Record<string, unknown> = {};
            if (filters.signal_type) f.signal_type = filters.signal_type;
            if (filters.status) f.status = filters.status;
            if (filters.search) f.search = filters.search;
            body.scope = { filter: f };
        } else {
            body.ids = Array.from(selectedIds.value);
        }

        const { data } = await axios.post('/api/projects/bulk', body);
        clearSelection();
        selectAllByFilter.value = false;
        await fetch();
        return data;
    }

    // Watch filter changes — clear selection on switch
    watch(
        () => [filters.signal_type, filters.status, filters.search, filters.region, filters.delivery_day] as const,
        () => {
            clearSelection();
            selectAllByFilter.value = false;
        },
    );

    function scheduleNext() {
        pollTimeout = setTimeout(async () => {
            pollTimeout = null;
            if (pendingIds.value.size === 0) {
                currentDelay = DELAY_OK;
                return;
            }
            try {
                const ids = Array.from(pendingIds.value).join(',');
                const { data } = await axios.get<{ data: Project[] }>('/api/projects', { params: { ids } });
                for (const project of data.data) {
                    const idx = items.value.findIndex((i) => i.id === project.id);
                    if (idx !== -1) items.value[idx] = project;
                    if (project.sync_status === 'ok' || project.sync_status === 'failed') {
                        pendingIds.value.delete(project.id);
                    }
                }
                currentDelay = DELAY_OK;
            } catch {
                // Exponential backoff to avoid hammering on transient errors.
                currentDelay = Math.min(currentDelay * 2, DELAY_MAX);
            }
            if (pendingIds.value.size > 0) {
                scheduleNext();
            }
        }, currentDelay);
    }

    function startPolling() {
        if (pollTimeout !== null) return;
        scheduleNext();
    }

    function stopPolling() {
        if (pollTimeout !== null) {
            clearTimeout(pollTimeout);
            pollTimeout = null;
        }
        currentDelay = DELAY_OK;
    }

    return {
        items,
        total,
        filters,
        selectedIds,
        pendingIds,
        loading,
        selectAllByFilter,
        fetch,
        create,
        update,
        del,
        syncNow,
        toggleActive,
        toggleSelect,
        clearSelection,
        bulkAction,
        bulkUpdate,
        startPolling,
        stopPolling,
    };
});
