'use strict';

// Debugging flag from URL or localStorage
let DEBUG = false;
try {
    const params = new URLSearchParams(window.location.search);
    if (params.has('debug')) {
        DEBUG = params.get('debug') === '1';
    }
    const lsDebug = localStorage.getItem('cvsmia_debug');
    if (lsDebug !== null) DEBUG = lsDebug === '1';
} catch {
    // ignore
}

(function markTrialIfNeeded() {
    const params = new URLSearchParams(window.location.search);
    const isTrial = params.get("trial") === "1";

    if (isTrial) {
        document.body.classList.add("trial");
    }
})();

function setDebug(on) {
    try { localStorage.setItem('cvsmia_debug', on ? '1' : '0'); } catch { }
    DEBUG = Boolean(on);
    return DEBUG;
}

function dbg(...args) {
    if (!DEBUG) return;
    try { console.log(...args); } catch { }
}

const isObject = v => v !== null && typeof v === 'object';

// Helper to create element with optional class and text content
function el(tag, cls, txt) {
    const e = document.createElement(tag);
    if (cls) e.className = cls;
    if (typeof txt !== 'undefined') e.textContent = txt;
    return e;
}

const I18N = Object.freeze({
    Viewer_ProfileImage: 'Profilbilde',
    Viewer_NoData: 'Ingen data',
    Viewer_MissingResumeElement: "Fant ikke element med id 'resume'",
    Viewer_RenderError: 'Feil ved rendering: {0}',
    Viewer_TailoredCvFor: 'Funksjonell CV for {0}',
    Viewer_Section_Work: 'Arbeidserfaring',
    Viewer_Section_Volunteer: 'Frivillig arbeid',
    Viewer_Section_Education: 'Utdanning',
    Viewer_Section_Projects: 'Prosjekter',
    Viewer_Section_Skills: 'Kompetanse',
    Viewer_Section_Awards: 'Utmerkelser',
    Viewer_Section_Publications: 'Publikasjoner',
    Viewer_Section_Certificates: 'Sertifikater',
    Viewer_Section_Languages: 'Språk',
    Viewer_Section_Interests: 'Interesser',
    Viewer_Section_References: 'Referanser',
    Viewer_Label_Courses: 'Kurs: {0}',
    Viewer_Label_Roles: 'Roller: {0}',
    Viewer_Label_For: 'For: {0}',
    Viewer_Label_Type: 'Type: {0}',
    Viewer_Label_Keywords: 'Stikkord: {0}'
});

function t(key, fallback) {
    try {
        const dict = window.CVSMIA_STRINGS || {};
        const value = dict[key];
        if (typeof value === 'string' && value.length > 0) return value;
    } catch {
        // ignore
    }
    return fallback || key;
}

function formatText(template, value) {
    return String(template).replace('{0}', value ?? '');
}

// Create external link safely
function createLink(href, text) {
    const raw = href ?? '';
    const norm = normalizeUrl(raw);

    // Hvis teksten er tom eller identisk med rå-URL-en,
    // bruk den normaliserte URL-en som visningstekst.
    const displayText = (!text || text === raw) ? norm : text;

    if (!norm || !isAllowedUrl(norm)) {
        return el('span', null, displayText || '');
    }

    const a = document.createElement('a');
    a.href = norm || '#';
    a.textContent = displayText || '';
    a.target = '_blank';
    a.rel = 'noopener noreferrer';
    a.title = displayText || norm || '';

    return a;
}




// Create list of items (li) from array of strings
function createList(items) {
    const ul = document.createElement('ul');
    items.forEach(item => {
        const li = document.createElement('li');
        li.textContent = item;
        ul.appendChild(li);
    });
    return ul;
}

// Safely convert value to string or empty string
function safeText(v) {
    return v === null || v === undefined ? '' : String(v);
}

function normalizeUrl(url) {
    if (!url) return '';
    const u = String(url).trim();
    const allowedSchemes = ['http', 'https', 'mailto', 'tel'];

    // Allerede absolutt URL
    if (/^[a-zA-Z]+:/.test(u)) {
        const scheme = u.split(':', 1)[0].toLowerCase();
        return allowedSchemes.includes(scheme) ? u : '';
    }

    // //example.com → https://example.com
    if (u.startsWith('//')) return 'https:' + u;

    // www.example.com → https://www.example.com
    if (u.startsWith('www.')) return 'https://' + u;

    // Enkel heuristikk: "enebakk.kommune.no" → https://enebakk.kommune.no
    if (!u.includes(' ') && u.includes('.') && !u.startsWith('/')) {
        return 'https://' + u;
    }

    // Ellers gjør vi ingenting (f.eks. relative stier)
    return u;
}

function getAllowedHosts() {
    const raw = (window.CVSMIA_ALLOWED_HOSTS || []);
    if (!Array.isArray(raw)) return [];
    return raw.map(entry => {
        if (!entry) return '';
        const trimmed = String(entry).trim().toLowerCase();
        if (!trimmed) return '';
        if (trimmed.includes('://')) {
            try { return new URL(trimmed).hostname.toLowerCase(); } catch { return ''; }
        }
        return trimmed;
    }).filter(Boolean);
}

function isHostAllowed(hostname) {
    if (!hostname) return false;
    const host = hostname.toLowerCase();
    const allow = getAllowedHosts();
    if (allow.length === 0) return false;
    for (const entry of allow) {
        if (entry.startsWith('.')) {
            if (host.endsWith(entry)) return true;
        } else if (host === entry) {
            return true;
        }
    }
    return false;
}

function isAllowedUrl(url) {
    if (!url) return false;
    if (!/^[a-zA-Z]+:/.test(url)) {
        return true; // relative paths are always allowed
    }
    try {
        const parsed = new URL(url);
        if (parsed.protocol === 'mailto:' || parsed.protocol === 'tel:') return true;
        if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false;
        return isHostAllowed(parsed.hostname);
    } catch {
        return false;
    }
}

function appendTokenToDataUrl(url, token) {
    if (!token) return url;
    try {
        const u = new URL(url, window.location.origin);
        if (u.pathname.startsWith('/data/')) {
            u.searchParams.set('t', token);
            return u.pathname + u.search;
        }
    } catch {
        // ignore
    }
    return url;
}




// --- NEW: avatar + photo helpers ---
function getInitials(name) {
    if (!name) return '•';
    const parts = String(name).trim().split(/\s+/).slice(0, 2);
    return parts.map(p => p[0]?.toUpperCase() || '').join('') || '•';
}

function createPhotoEl(src, alt) {
    const img = document.createElement('img');
    img.className = 'photo';
    img.alt = alt || t('Viewer_ProfileImage', I18N.Viewer_ProfileImage);
    img.decoding = 'async';
    img.loading = 'lazy';
    img.referrerPolicy = 'no-referrer';
    img.src = src;
    return img;
}

function createAvatarEl(initials) {
    const div = document.createElement('div');
    div.className = 'avatar';
    div.textContent = initials || '•';
    return div;
}
// --- end NEW helpers ---

// Format date range formatted as "Fra – Til" with en dash (–)
function dateMeta(start, end) {
    if (!start && !end) return '';
    if (start && !end) return String(start);
    if (!start && end) return `– ${end}`;
    return `${start} – ${end}`;
}

// Fix malformed items where keys contain colon-separated 'key: value' strings,
// and convert an object mapping keys to identical values to array.
function fixItem(it) {
    if (it == null) return it; // null or undefined
    if (Array.isArray(it)) return it.map(fixItem);
    if (isObject(it)) {
        const keys = Object.keys(it);
        if (keys.length === 0) return {};

        const hasColonKey = keys.some(k => k.includes(': '));
        if (hasColonKey) {
            const res = {};
            for (const k of keys) {
                const parts = k.split(': ');
                const field = parts[0].trim();
                const inlineVal = parts.slice(1).join(': ').trim();
                const raw = it[k];
                if (isObject(raw)) res[field] = fixItem(raw);
                else if (inlineVal) res[field] = inlineVal;
                else res[field] = raw;
            }
            return res;
        }

        // Recursively fix values
        const fixed = {};
        for (const k of keys) {
            fixed[k] = fixItem(it[k]);
        }

        // If all values are primitives and equal their keys, convert to array
        const allValuesPrimitive = keys.every(k => !isObject(it[k]));
        const allValuesEqualKeys = allValuesPrimitive && keys.every(k => String(it[k]) === String(k));
        if (allValuesEqualKeys) return keys.slice();

        return fixed;
    }

    return it;
}

// Normalize section data into an array of items or primitives
function normalizeSection(v) {
    if (!v) return [];
    if (Array.isArray(v)) {
        return v.flatMap(elm => {
            if (elm && isObject(elm) && !Array.isArray(elm)) {
                const keys = Object.keys(elm);
                if (keys.length === 1 && isObject(elm[keys[0]])) {
                    return fixItem(elm[keys[0]]);
                }
                return fixItem(elm);
            }
            return elm;
        });
    }

    if (isObject(v)) {
        const keys = Object.keys(v);
        if (keys.length === 0) return [];

        // If object looks like a single item (has common fields), wrap into array
        const sampleProps = ['name', 'position', 'institution', 'title', 'summary', 'description', 'url'];
        if (keys.some(k => sampleProps.includes(k))) {
            return [fixItem(v)];
        }

        // If values are objects, return array of fixed values
        if (keys.every(k => v[k] && isObject(v[k]))) {
            return keys.map(k => fixItem(v[k]));
        }

        // Otherwise treat as array of primitives or fixed objects
        return keys.map(k => fixItem(v[k]));
    }

    return [v];
}

async function render(data) {
    try {
        const container = document.getElementById("resume");
        if (!container) throw new Error(t('Viewer_MissingResumeElement', I18N.Viewer_MissingResumeElement));

        container.innerHTML = '';
        if (!data) {
            container.textContent = t('Viewer_NoData', I18N.Viewer_NoData);
            return;
        }

        try { data = fixItem(data); } catch { }

        const basics = data.basics || {};

        dbg('render: basics sample', basics);
        try {
            dbg('render: basics JSON', JSON.stringify(basics, null, 2));
        } catch { }

        const header = el('header');

        // --- NEW: robust håndtering av bilde/ingen bilde/feil lastering ---
        const imgUrl = basics.image || basics.picture || '';
        const safeImgUrl = normalizeUrl(imgUrl);
        let leftEl;
        if (safeImgUrl && isAllowedUrl(safeImgUrl)) {
            const photo = createPhotoEl(safeImgUrl, safeText(basics.name) || t('Viewer_ProfileImage', I18N.Viewer_ProfileImage));
            // Fallback til avatar hvis bildet feiler
            photo.addEventListener('error', () => {
                const avatar = createAvatarEl(getInitials(basics.name));
                header.classList.add('no-photo');
                try { header.replaceChild(avatar, photo); } catch { /* ignore */ }
            }, { once: true });
            leftEl = photo;
        } else {
            leftEl = createAvatarEl(getInitials(basics.name));
            header.classList.add('no-photo');
        }
        // --- end NEW ---

        const info = el('div', 'info');
        info.appendChild(el('h1', null, formatText(t('Viewer_TailoredCvFor', I18N.Viewer_TailoredCvFor), safeText(basics.name))));
        if (basics.label) info.appendChild(el('div', 'muted', basics.label));

        const loc = basics.location || {};
        const locParts = [loc.address, loc.postalCode, loc.city, loc.region, loc.countryCode].filter(Boolean);
        const locStr = locParts.join(', ');

        const contactElems = [basics.email, basics.phone, basics.url, locStr].filter(Boolean);
        if (contactElems.length) {
            const contactLine = contactElems.join(' \u2022 ');
            const contact = el('div', 'muted contact', contactLine);
            info.appendChild(contact);
        }

        if (Array.isArray(basics.profiles) && basics.profiles.length) {
            const profilesDiv = el('div', 'profiles');
            basics.profiles.forEach(p => {
                const label = p.network
                    ? p.network + (p.username ? `: ${p.username}` : '')
                    : p.username || p.url || '';
                const a = createLink(p.url, label);
                profilesDiv.appendChild(a);
                profilesDiv.appendChild(document.createTextNode(' '));
            });
            info.appendChild(profilesDiv);
        }

        // Venstre + høyre kolonne
        if (leftEl) header.appendChild(leftEl);
        header.appendChild(info);
        container.appendChild(header);

        if (basics.summary) {
            const summaryDiv = el('div', 'summary');
            const p = el('p', null, basics.summary);
            summaryDiv.appendChild(p);
            container.appendChild(summaryDiv);
        }

        const sections = [
            { key: 'work', title: t('Viewer_Section_Work', I18N.Viewer_Section_Work), renderItem: renderWorkItem },
            { key: 'volunteer', title: t('Viewer_Section_Volunteer', I18N.Viewer_Section_Volunteer), renderItem: renderVolunteerItem },
            { key: 'education', title: t('Viewer_Section_Education', I18N.Viewer_Section_Education), renderItem: renderEducationItem },
            { key: 'projects', title: t('Viewer_Section_Projects', I18N.Viewer_Section_Projects), renderItem: renderProjectItem },
            { key: 'skills', title: t('Viewer_Section_Skills', I18N.Viewer_Section_Skills), renderItem: renderSkillItem },
            { key: 'awards', title: t('Viewer_Section_Awards', I18N.Viewer_Section_Awards), renderItem: renderAwardItem },
            { key: 'publications', title: t('Viewer_Section_Publications', I18N.Viewer_Section_Publications), renderItem: renderPublicationItem },
            { key: 'certificates', title: t('Viewer_Section_Certificates', I18N.Viewer_Section_Certificates), renderItem: renderCertificateItem },
            { key: 'languages', title: t('Viewer_Section_Languages', I18N.Viewer_Section_Languages), renderItem: renderLanguageItem },
            { key: 'interests', title: t('Viewer_Section_Interests', I18N.Viewer_Section_Interests), renderItem: renderInterestItem },
            { key: 'references', title: t('Viewer_Section_References', I18N.Viewer_Section_References), renderItem: renderReferenceItem },
        ];

        for (const { key, title, renderItem } of sections) {
            const items = normalizeSection(data[key]);
            dbg(`render: ${key} sample JSON`, JSON.stringify(items.slice(0, 3), null, 2));
            if (items.length === 0) continue;

            const sectionEl = el('section', 'section');
            sectionEl.appendChild(el('h2', null, title));

            items.forEach(item => {
                const rendered = renderItem(item);
                if (rendered) sectionEl.appendChild(rendered);
            });

            container.appendChild(sectionEl);
        }

        await waitForResources();

        dbg('render completed, resume children:', container.childElementCount);
        dbg('resume innerHTML sample:', container.innerHTML.slice(0, 2000));
        window.dispatchEvent(new Event('resume-view-rendered'));
    } catch (err) {
        console.error('render() failed:', err);
        const fallback = document.getElementById("resume");
        if (fallback) fallback.textContent = formatText(t('Viewer_RenderError', I18N.Viewer_RenderError), err?.message ?? String(err));
    }
}

// Helpers to render each item type for sections

function renderWorkItem(w) {
    if (!w) return null;
    const item = el('div', 'item');
    const titleText = w.position ? `${w.position} — ${w.name || ''}` : (w.name || '');
    item.appendChild(el('h3', null, titleText.trim()));

    const meta = dateMeta(w.startDate, w.endDate);
    if (meta) item.appendChild(el('div', 'muted', meta));
    if (w.location) item.appendChild(el('div', 'muted', w.location));
    if (w.description) item.appendChild(el('p', null, w.description));
    if (w.summary && !w.description) item.appendChild(el('p', null, w.summary));
    if (w.url) item.appendChild(createLink(w.url, w.url));
    if (Array.isArray(w.highlights) && w.highlights.length) item.appendChild(createList(w.highlights));
    return item;
}

function renderVolunteerItem(v) {
    if (!v) return null;
    const item = el('div', 'item');
    const titleText = v.position ? `${v.position} — ${v.organization || ''}` : (v.organization || '');
    item.appendChild(el('h3', null, titleText.trim()));

    const meta = dateMeta(v.startDate, v.endDate);
    if (meta) item.appendChild(el('div', 'muted', meta));
    if (v.summary) item.appendChild(el('p', null, v.summary));
    if (v.url) item.appendChild(createLink(v.url, v.url));
    if (Array.isArray(v.highlights) && v.highlights.length) item.appendChild(createList(v.highlights));
    return item;
}

function renderEducationItem(ed) {
    if (!ed) return null;
    const item = el('div', 'item');
    const titleContent = safeText(ed.institution) + (ed.area ? ` — ${safeText(ed.area)}` : '');
    item.appendChild(el('h3', null, titleContent.trim()));

    const parts = [];
    if (ed.studyType) parts.push(ed.studyType);
    const dateStr = dateMeta(ed.startDate, ed.endDate);
    if (dateStr) parts.push(dateStr);

    if (parts.length) item.appendChild(el('div', 'muted', parts.join(' \u2022 ')));

    if (ed.url) item.appendChild(createLink(ed.url, ed.url));
    if (ed.score || ed.gpa) item.appendChild(el('div', 'muted', ed.score || ed.gpa));
    if (Array.isArray(ed.courses) && ed.courses.length) {
        const p = el('div', null, formatText(t('Viewer_Label_Courses', I18N.Viewer_Label_Courses), ed.courses.join(', ')));
        item.appendChild(p);
    }
    return item;
}

function renderProjectItem(p) {
    if (!p) return null;
    const item = el('div', 'item');
    item.appendChild(el('h3', null, p.name || ''));

    const meta = dateMeta(p.startDate, p.endDate);
    if (meta) item.appendChild(el('div', 'muted', meta));
    if (p.description) item.appendChild(el('p', null, p.description));
    if (Array.isArray(p.roles) && p.roles.length) item.appendChild(el('div', null, formatText(t('Viewer_Label_Roles', I18N.Viewer_Label_Roles), p.roles.join(', '))));
    if (p.entity) item.appendChild(el('div', 'muted', formatText(t('Viewer_Label_For', I18N.Viewer_Label_For), p.entity)));
    if (p.type) item.appendChild(el('div', 'muted', formatText(t('Viewer_Label_Type', I18N.Viewer_Label_Type), p.type)));
    if (Array.isArray(p.keywords) && p.keywords.length) item.appendChild(el('div', null, formatText(t('Viewer_Label_Keywords', I18N.Viewer_Label_Keywords), p.keywords.join(', '))));
    if (Array.isArray(p.highlights) && p.highlights.length) item.appendChild(createList(p.highlights));
    if (p.url) item.appendChild(createLink(p.url, p.url));
    return item;
}

function renderSkillItem(s) {
    if (!s) return null;
    const item = el('div', 'item');
    item.appendChild(el('h3', null, s.name || ''));
    if (s.level) item.appendChild(el('div', 'muted', s.level));
    if (Array.isArray(s.keywords) && s.keywords.length) item.appendChild(el('div', null, s.keywords.join(', ')));
    return item;
}

function renderAwardItem(a) {
    if (!a) return null;
    const item = el('div', 'item');
    item.appendChild(el('h3', null, a.title || ''));
    if (a.awarder || a.date) item.appendChild(el('div', 'muted', [a.awarder, a.date].filter(Boolean).join(' \u2022 ')));
    if (a.url) item.appendChild(createLink(a.url, a.url));
    if (a.summary) item.appendChild(el('p', null, a.summary));
    return item;
}

function renderPublicationItem(pub) {
    if (!pub) return null;
    const item = el('div', 'item');
    item.appendChild(el('h3', null, pub.name || ''));
    if (pub.publisher || pub.releaseDate) item.appendChild(el('div', 'muted', [pub.publisher, pub.releaseDate].filter(Boolean).join(' \u2022 ')));
    if (pub.summary) item.appendChild(el('p', null, pub.summary));
    if (pub.url) item.appendChild(createLink(pub.url, pub.url));
    return item;
}

function renderCertificateItem(c) {
    if (!c) return null;
    const item = el('div', 'item');
    const titleText = safeText(c.name) + (c.issuer ? ` — ${safeText(c.issuer)}` : '');
    item.appendChild(el('h3', null, titleText.trim()));

    if (c.date) {
        const timeEl = document.createElement('time');
        timeEl.className = 'muted';
        timeEl.dateTime = c.date;
        timeEl.textContent = c.date;
        item.appendChild(timeEl);
    }
    if (c.url) {
        item.appendChild(document.createTextNode(' '));
        item.appendChild(createLink(c.url, c.url));
    }
    return item;
}

function renderLanguageItem(l) {
    if (!l) return null;
    const item = el('div', 'item');
    const text = safeText(l.language) + (l.fluency ? ` — ${safeText(l.fluency)}` : '');
    item.appendChild(el('div', null, text.trim()));
    return item;
}

function renderInterestItem(i) {
    if (!i) return null;
    const item = el('div', 'item');
    item.appendChild(el('h3', null, safeText(i.name)));
    if (Array.isArray(i.keywords) && i.keywords.length) item.appendChild(el('div', null, i.keywords.join(', ')));
    return item;
}

function renderReferenceItem(r) {
    if (!r) return null;
    const item = el('div', 'item');
    item.appendChild(el('div', null, safeText(r.name)));
    if (r.reference) item.appendChild(el('div', null, safeText(r.reference)));
    return item;
}

// Wait for all images and fonts (if supported) to finish loading
async function waitForResources() {
    try {
        const imgs = Array.from(document.images || []);
        const fontReady = (document.fonts && document.fonts.ready) ? document.fonts.ready : Promise.resolve();

        const loadPromises = imgs.map(img => {
            if (img.complete) return Promise.resolve();
            return new Promise(resolve => {
                img.addEventListener('load', resolve, { once: true, passive: true });
                img.addEventListener('error', resolve, { once: true, passive: true });
            });
        });

        await Promise.all([fontReady, ...loadPromises]);
    } catch {
        // Ignore any errors here
    }
}

document.addEventListener("DOMContentLoaded", async () => {
    const resumeContainer = document.getElementById("resume");

    // Automatisk visning via ?data=filnavn
    try {
        const params = new URLSearchParams(window.location.search);
        let dataFile = params.get("data");
        const dataToken = params.get("t");
        if (dataFile) {
            // Hvis filnavn, prepender vi /data/
            if (!dataFile.startsWith('/') && !dataFile.startsWith('http') && !dataFile.startsWith('file:') &&
                !/^[a-zA-Z]:\\/.test(dataFile) && !/^\\\\/.test(dataFile)) {
                dataFile = `/data/${dataFile}`;
            }
            dataFile = appendTokenToDataUrl(dataFile, dataToken);

            try {
                const response = await fetch(dataFile, { cache: 'no-store' });
                if (!response.ok) throw new Error(`HTTP ${response.status}`);
                const json = await response.json();
                await render(json);
            } catch (fetchErr) {
                if (resumeContainer) resumeContainer.textContent = t('Viewer_NoData', I18N.Viewer_NoData);
                // Fallback for lokale stier
                if (dataFile.startsWith('file:') || /^[a-zA-Z]:\\/.test(dataFile) || /^\\\\/.test(dataFile)) {
                    try {
                        const resp2 = await fetch(dataFile);
                        const txt2 = await resp2.text();
                        await render(JSON.parse(txt2));
                    } catch {
                        // Ignorer andre feil
                    }
                }
            }
        }
    } catch {
        // Ignorer alle feil
    }

    // Ingen fil-opplasting i viewer (data kommer via in-memory endpoint)
});

// Auto print support: ?autoprint=1 in URL triggers print after render
(function autoPrint() {
    try {
        const params = new URLSearchParams(location.search);
        const doAutoPrint = params.get('autoprint') === '1';
        if (!doAutoPrint) return;

        let printed = false;

        function tryPrint() {
            if (printed) return;
            printed = true;
            // Wait two animation frames for layout stabilization before printing.
            requestAnimationFrame(() => requestAnimationFrame(() => {
                try { window.print(); } catch { /* ignore */ }
            }));
        }

        window.addEventListener('resume-view-rendered', tryPrint, { once: true, passive: true });
        window.addEventListener('load', () => {
            setTimeout(() => {
                if (!printed) tryPrint();
            }, 1200);
        }, { passive: true });
    } catch {
        // fail silently
    }
})();
