/**
 * @file ticketApi.js
 * @description API-anrop mot Spark (spark.iver.com/api)
 * 
 * Author: Linus Olofsson - Iver 
 * Date: 2026-02-18
 * Last modified: Linus Olofsson (2026-02-24) - Direkta anrop mot spark.iver.com/api
 * 
 * @purpose Hantera alla ticket-relaterade API-anrop mot Spark
 * @invoked_by serviceWorker.js
 */

import { makeAuthenticatedRequest, getLoggedInUserId, SPARK_API_BASE } from './auth.js';

// Mappning: bas-artikel GUID:er (ej overtime) per rollkategori
const ARTICLE_GUID_MAP = {
    'Specialist':                    '243b745f-0000-0000-48c7-7f2700000000', // articleId 20000
    'Senior Specialist':             '243b745f-0000-0000-438c-c13c00000000', // articleId 21000
    'Technical Consultant':          '243b745f-0000-0000-6524-321400000000', // articleId 11000
    'Senior Technical Consultant':   '243b745f-0000-0000-9ed0-551000000000', // articleId 12000
    'Junior Technical Consultant':   '243b745f-0000-0000-59a2-ed0c00000000', // articleId 10000
    'Project Manager':               '243b745f-0000-0000-f3cb-ea1b00000000', // articleId 30000
    'Senior Project Manager':        '243b745f-0000-0000-2c78-0e1800000000', // articleId 31000
};

// Reverse-lookup: GUID → rollnamn
const ARTICLE_GUID_TO_NAME = Object.fromEntries(
    Object.entries(ARTICLE_GUID_MAP).map(([name, guid]) => [guid, name])
);

/**
 * Mappa en artikel-GUID tillbaka till rollnamn (t.ex. "Specialist", "Senior Technical Consultant").
 * Returnerar null om GUID:et inte hittas.
 */
function getArticleNameByGuid(articleGuid) {
    return ARTICLE_GUID_TO_NAME[articleGuid] || null;
}

// Alla overtime GUID:er — dessa ska ignoreras vid kontroll
const OVERTIME_ARTICLE_GUIDS = new Set([
    '243b745f-0000-0000-6e8f-970f00000000', // Specialist - Qualified overtime
    '243b745f-0000-0000-5bab-8b3b00000000', // Specialist - Regular overtime
    '243b745f-0000-0000-6954-d92400000000', // Senior Specialist - Qualified overtime
    '243b745f-0000-0000-5670-cd1000000000', // Senior Specialist - Regular overtime
    '243b745f-0000-0000-8bec-493c00000000', // Technical Consultant - Qualified overtime
    '243b745f-0000-0000-7808-3e2800000000', // Technical Consultant - Regular overtime
    '243b745f-0000-0000-c498-6d3800000000', // Senior Technical Consultant - Qualified overtime
    '243b745f-0000-0000-b1b4-612400000000', // Senior Technical Consultant - Regular overtime
    '243b745f-0000-0000-7f6a-053500000000', // Junior Technical Consultant - Qualified overtime
    '243b745f-0000-0000-6c86-f92000000000', // Junior Technical Consultant - Regular overtime
    '243b745f-0000-0000-1994-020400000000', // Project Manager - Qualified overtime
    '243b745f-0000-0000-06b0-f62f00000000', // Project Manager - Regular overtime
    '243b745f-0000-0000-5240-260000000000', // Senior Project Manager - Qualified overtime
    '243b745f-0000-0000-3f5c-1a2c00000000', // Senior Project Manager - Regular overtime
    '243b745f-0000-0000-5e8d-d01f00000000', // Jour telefoni
]);

/**
 * Mappa en Spark assignedTo.title (t.ex. "IT Specialist", "Network Specialist")
 * till rätt bas-artikel GUID.
 * - Om titeln innehåller "Senior" + "Specialist" → Senior Specialist
 * - Om titeln innehåller "Specialist" (utan Senior) → Specialist
 * - Om titeln innehåller "Junior" + "Technical" → Junior Technical Consultant
 * - Om titeln innehåller "Senior" + "Technical Consultant" → Senior Technical Consultant
 * - Om titeln innehåller "Technical Consultant" → Technical Consultant
 * - Om titeln innehåller "Senior" + "Project Manager" → Senior Project Manager
 * - Om titeln innehåller "Project Manager" → Project Manager
 */
function getExpectedArticleGuid(assignedToTitle) {
    if (!assignedToTitle) return null;
    const t = assignedToTitle.toLowerCase();
    const isSenior = t.includes('senior');
    const isJunior = t.includes('junior');

    if (t.includes('specialist')) {
        return ARTICLE_GUID_MAP[isSenior ? 'Senior Specialist' : 'Specialist'];
    }
    if (isJunior && t.includes('technical')) {
        return ARTICLE_GUID_MAP['Junior Technical Consultant'];
    }
    if (t.includes('technical consultant')) {
        return ARTICLE_GUID_MAP[isSenior ? 'Senior Technical Consultant' : 'Technical Consultant'];
    }
    if (t.includes('project manager')) {
        return ARTICLE_GUID_MAP[isSenior ? 'Senior Project Manager' : 'Project Manager'];
    }

    console.warn(`No article mapping found for title: "${assignedToTitle}"`);
    return null;
}

/**
 * Hämta timesheets för ett ärende
 * Endpoint: POST /api/Tickets/TimeSheets
 */
async function getTicketTimeSheets(ticketId) {
    const url = `${SPARK_API_BASE}/Tickets/TimeSheets`;

    // Max 7 dagar bakåt i tiden
    const sevenDaysAgo = new Date();
    sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
    const fromDate = sevenDaysAgo.toISOString();

    try {
        const result = await makeAuthenticatedRequest(url, {
            method: 'POST',
            body: JSON.stringify({
                skip: 0,
                take: 100,
                sort: [{ selector: 'performedDate', desc: true }],
                ticketId: ticketId,
                articleId: null,
                fromDateInclusive: fromDate,
                toDateInclusive: null,
                userCuid: null
            })
        });
        return result || [];
    } catch (error) {
        console.error(`Error fetching timesheets for ticket ${ticketId}:`, error);
        return [];
    }
}

// Status-ID:n som ska exkluderas (stängda/lösta/avbrutna)
const EXCLUDED_STATUS_IDS = [
    '3efc9f1f-0000-0000-bac3-561f00000000', // Ready for customer
    '3efc9f1f-0000-0000-457a-f83200000000', // Solved
    '3efc9f1f-0000-0000-585e-040700000000', // Utford
    '3efc9f1f-0000-0000-cda7-623300000000', // Avslutad
    '3efc9f1f-0000-0000-ad59-991200000000', // Closed by serviceteam
    '3efc9f1f-0000-0000-f9e9-c82200000000', // Avbruten
    '3efc9f1f-0000-0000-0cce-d43600000000', // Analyzing
    '3efc9f1f-0000-0000-1fb2-e00a00000000'  // Evaluated
];

/**
 * Hämta tickets tilldelade mig via Tickets/Search
 * Endpoint: POST /api/Tickets/Search
 */
async function getMyTickets() {
    const url = `${SPARK_API_BASE}/Tickets/Search`;
    
    const excludeFilter = EXCLUDED_STATUS_IDS.reduce((acc, id, i) => {
        if (i > 0) acc.push('or');
        acc.push(['status.id', '=', id]);
        return acc;
    }, []);

    const searchBody = {
        filter: [
            ['!', excludeFilter],
            'and',
            ['assignedTo.id', '=', 'PLACEHOLDER']
        ],
        sort: [{ selector: 'changedDate', desc: true }],
        getAll: true,
        getAllLimit: 200,
        escape: true,
        isTemplateFilter: false,
        statusIsActive: true,
        searchOperation: 'contains',
        searchValue: null,
        fullTextSearch: null,
        assignedToIdFilter: null,
        assignedDepartmentIdFilter: null,
        isOwnershipExternalFilter: null,
        supportGroupIdFilter: null,
        group: [],
        userData: {}
    };

    const userId = await getLoggedInUserId();
    if (!userId) throw new Error('Could not determine logged-in user ID');

    searchBody.filter[2] = ['assignedTo.id', '=', userId];

    console.log('Fetching "My Tickets" from Spark API via Tickets/Search for user:', userId);
    
    try {
        const result = await makeAuthenticatedRequest(url, {
            method: 'POST',
            body: JSON.stringify(searchBody)
        });
        const tickets = result?.data || result;
        console.log(`Successfully fetched ${tickets?.length || 0} tickets from "My Tickets"`);
        return tickets || [];
    } catch (error) {
        console.error('Error fetching My Tickets:', error);
        throw error;
    }
}

/**
 * Hämta SavedView-konfiguration
 * @param {string} viewId - SavedView-ID
 */
async function getSavedView(viewId) {
    const url = `${SPARK_API_BASE}/SavedViews/${viewId}`;
    
    console.log('Fetching saved view:', viewId);
    
    try {
        const view = await makeAuthenticatedRequest(url, { method: 'GET' });
        console.log('Successfully fetched saved view:', view?.name);
        return view;
    } catch (error) {
        console.error('Error fetching saved view:', error);
        throw error;
    }
}

/**
 * Hämta en specifik ticket
 * Endpoint: GET /api/Tickets/{ticketId}
 */
async function getTicketById(ticketId) {
    const url = `${SPARK_API_BASE}/Tickets/${ticketId}`;
    
    console.log('Fetching ticket by ID:', ticketId);
    
    try {
        const ticket = await makeAuthenticatedRequest(url, { method: 'GET' });
        console.log('Successfully fetched ticket:', ticket?.ticketId);
        return ticket;
    } catch (error) {
        console.error('Error fetching ticket:', error);
        throw error;
    }
}

/**
 * Hämta alla sparade vyer
 * Endpoint: GET /api/SavedViews?savedViewType=SparkTicketList
 */
async function getSavedViews() {
    const url = `${SPARK_API_BASE}/SavedViews?savedViewType=SparkTicketList`;
    
    console.log('Fetching saved views...');
    
    try {
        const views = await makeAuthenticatedRequest(url, { method: 'GET' });
        console.log(`Successfully fetched ${views?.length || 0} saved views`);
        return views || [];
    } catch (error) {
        console.error('Error fetching saved views:', error);
        throw error;
    }
}

/**
 * Hämta alla ticket kinds (typer)
 * Endpoint: GET /api/TicketSettings/TicketKinds
 */
async function getTicketKinds() {
    const url = `${SPARK_API_BASE}/TicketSettings/TicketKinds`;
    
    try {
        const kinds = await makeAuthenticatedRequest(url, { method: 'GET' });
        return kinds || [];
    } catch (error) {
        console.error('Error fetching ticket kinds:', error);
        throw error;
    }
}

/**
 * Hämta SLA-preview för ett ärende
 * Endpoint: POST /api/SLALevels/PreviewSLA
 */
async function previewSLA(customerId, customerServiceId, ticketKindId, ticketPriorityId) {
    const url = `${SPARK_API_BASE}/SLALevels/PreviewSLA`;
    
    const payload = {
        customerId,
        customerServiceId,
        ticketKindId,
        ticketPriorityId
    };
    
    try {
        const sla = await makeAuthenticatedRequest(url, {
            method: 'POST',
            body: JSON.stringify(payload)
        });
        return sla;
    } catch (error) {
        console.error('Error fetching SLA preview:', error);
        throw error;
    }
}

/**
 * Transformera DevExtreme filterValue till Tickets/Search-kompatibelt format.
 * Konverterar 'noneof' → ['!', [... 'or' ...]] och 'anyof' → [... 'or' ...]
 * Rekursivt: hanterar 'and'/'or'-kedjor.
 */
function transformFilter(filter) {
    if (!Array.isArray(filter) || filter.length === 0) return filter;

    // Kolla om detta är en trippel: [field, operator, value]
    if (filter.length === 3 && typeof filter[0] === 'string' && typeof filter[1] === 'string') {
        const [field, op, value] = filter;

        if (op === 'noneof' && Array.isArray(value)) {
            // ["status.id", "noneof", ["a","b","c"]] → ["!", [["status.id","=","a"],"or",["status.id","=","b"],"or",...]]
            const orParts = [];
            for (let i = 0; i < value.length; i++) {
                if (i > 0) orParts.push('or');
                orParts.push([field, '=', value[i]]);
            }
            console.log(`[CUSTOM-QUEUE] Transformed noneof on "${field}" (${value.length} values) to negated OR`);
            return ['!', orParts];
        }

        if (op === 'anyof' && Array.isArray(value)) {
            // ["field", "anyof", ["a","b"]] → [["field","=","a"],"or",["field","=","b"]]
            const orParts = [];
            for (let i = 0; i < value.length; i++) {
                if (i > 0) orParts.push('or');
                orParts.push([field, '=', value[i]]);
            }
            return orParts;
        }

        // Vanlig trippel — returnera som den är
        return filter;
    }

    // Rekursiv: hantera 'and'/'or'-kedjor — [expr, 'and', expr, 'and', ...]
    return filter.map(item => {
        if (Array.isArray(item)) return transformFilter(item);
        return item; // 'and', 'or', '!'
    });
}

/**
 * Hämta alla tickets från en specifik SavedView (kö)
 * Använder SavedView-konfigurationen + POST /api/Tickets/Search
 * @param {string} viewId - SavedView-ID
 * @returns {Array} Lista med tickets
 */
async function getTicketsFromView(viewId) {
    console.log(`[CUSTOM-QUEUE] Fetching tickets for savedView: ${viewId}`);

    try {
        // Steg 1: Hämta SavedView-konfigurationen
        const viewConfig = await getSavedView(viewId);
        if (!viewConfig) {
            console.error(`[CUSTOM-QUEUE] Could not load view config for ${viewId}`);
            return [];
        }
        console.log(`[CUSTOM-QUEUE] View "${viewConfig.name}" loaded`);

        const gridState = viewConfig.devExtremeDataGridState;
        if (!gridState) {
            console.error(`[CUSTOM-QUEUE] View "${viewConfig.name}" has no devExtremeDataGridState`);
            return [];
        }

        // Steg 2: Bygg filter från kolumndefinitioner (skippa status.id — vi lägger alltid till egen)
        const columns = gridState.columns || [];
        const filterParts = [];

        for (const col of columns) {
            if (!col.dataField || !col.filterValues || col.filterValues.length === 0) continue;
            // Skippa status.id-filter från vyn — vi ersätter med vår egna nedan
            if (col.dataField === 'status.id') continue;

            if (col.filterType === 'exclude') {
                const orParts = [];
                for (let i = 0; i < col.filterValues.length; i++) {
                    if (i > 0) orParts.push('or');
                    orParts.push([col.dataField, '=', col.filterValues[i]]);
                }
                filterParts.push(['!', orParts]);
                console.log(`[CUSTOM-QUEUE] Column "${col.dataField}": exclude ${col.filterValues.length} values`);
            } else if (col.filterType === 'include') {
                const orParts = [];
                for (let i = 0; i < col.filterValues.length; i++) {
                    if (i > 0) orParts.push('or');
                    orParts.push([col.dataField, '=', col.filterValues[i]]);
                }
                filterParts.push(orParts.length === 1 ? orParts[0] : orParts);
                console.log(`[CUSTOM-QUEUE] Column "${col.dataField}": include ${col.filterValues.length} values`);
            }
        }

        // Alltid exkludera stängda/lösta statusar för custom queues
        {
            const orParts = [];
            for (let i = 0; i < EXCLUDED_STATUS_IDS.length; i++) {
                if (i > 0) orParts.push('or');
                orParts.push(['status.id', '=', EXCLUDED_STATUS_IDS[i]]);
            }
            filterParts.push(['!', orParts]);
            console.log(`[CUSTOM-QUEUE] Injected mandatory status exclude (${EXCLUDED_STATUS_IDS.length} statuses)`);
        }

        // Kombinera alla filter med 'and'
        let filter = [];
        if (filterParts.length === 1) {
            filter = filterParts[0];
        } else if (filterParts.length > 1) {
            for (let i = 0; i < filterParts.length; i++) {
                if (i > 0) filter.push('and');
                filter.push(filterParts[i]);
            }
        }

        // Extrahera sortering från kolumner (de med sortOrder)
        const sortColumns = columns
            .filter(c => c.sortOrder && c.dataField)
            .sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0));
        const sort = sortColumns.length > 0
            ? sortColumns.map(c => ({ selector: c.dataField, desc: c.sortOrder === 'desc' }))
            : [{ selector: 'changedDate', desc: true }];

        // Steg 3: Bygg Tickets/Search body
        const searchBody = {
            filter: filter,
            sort: sort,
            getAll: true,
            getAllLimit: 200,
            escape: true,
            isTemplateFilter: false,
            statusIsActive: null,
            searchOperation: 'contains',
            searchValue: null,
            fullTextSearch: viewConfig.freeTextSearch || null,
            assignedToIdFilter: null,
            assignedDepartmentIdFilter: null,
            isOwnershipExternalFilter: null,
            supportGroupIdFilter: null,
            group: [],
            userData: {}
        };

        const url = `${SPARK_API_BASE}/Tickets/Search`;
        console.log(`[CUSTOM-QUEUE] POSTing to ${url} for view "${viewConfig.name}", ${filterParts.length} filter conditions`);

        const result = await makeAuthenticatedRequest(url, {
            method: 'POST',
            body: JSON.stringify(searchBody)
        });

        const tickets = result?.data || result;
        console.log(`[CUSTOM-QUEUE] Fetched ${Array.isArray(tickets) ? tickets.length : 0} tickets from view "${viewConfig.name}"`);
        return Array.isArray(tickets) ? tickets : [];
    } catch (error) {
        console.error(`[CUSTOM-QUEUE] Error fetching tickets from view ${viewId}:`, error);
        return [];
    }
}

export {
    getMyTickets,
    getSavedView,
    getTicketById,
    getSavedViews,
    getTicketKinds,
    previewSLA,
    getTicketTimeSheets,
    getTicketsFromView,
    getExpectedArticleGuid,
    getArticleNameByGuid,
    EXCLUDED_STATUS_IDS,
    OVERTIME_ARTICLE_GUIDS
};
