window.EditorMovie = (function () {
    'use strict';

    var STORAGE_KEY = 'omdb-api-key';

    var BEGIN = '<!-- BEGIN MOVIE -->';
    var END = '<!-- END MOVIE -->';

    function firstHeading(text) {
        var m = text.match(/^#{1,6}\s+(.+?)\s*$/m);
        return m ? m[1].trim() : '';
    }

    function parseTitleYear(raw) {
        var m = raw.match(/^(.+?)\s*\((\d{4})\)\s*$/);
        return m ? { title: m[1].trim(), year: m[2] } : { title: raw.trim(), year: null };
    }

    function safe(v) { return (!v || v === 'N/A') ? '' : String(v); }

    function esc(s) {
        return String(s)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;');
    }

    function buildBlock(m) {
        var out = [BEGIN, '<aside class="movie-info">'];
        if (m.Poster && m.Poster !== 'N/A') {
            out.push('<img class="movie-poster" src="' + esc(m.Poster) +
                     '" alt="' + esc(safe(m.Title)) + ' poster">');
        }
        out.push('<table>');
        [
            ['Title',    m.Title],
            ['Year',     m.Year],
            ['Runtime',  m.Runtime],
            ['Genre',    m.Genre],
            ['Director', m.Director],
            ['Cast',     m.Actors],
            ['Plot',     m.Plot],
        ].forEach(function (r) {
            out.push('<tr><th>' + r[0] + '</th><td>' + esc(safe(r[1])) + '</td></tr>');
        });
        out.push('</table>', '</aside>', END);
        return out.join('\n');
    }

    // ctx is the CM adapter from main.js: { getValue(), replace(start,end,text) }.
    function insertOrReplace(ctx, markup) {
        var t = ctx.getValue() || '';
        var b = t.indexOf(BEGIN);
        var e = t.indexOf(END);
        if (b !== -1 && e !== -1 && e > b) {
            ctx.replace(b, e + END.length, markup);
        } else {
            var h = t.match(/^#{1,6}\s+.+?\s*$/m);
            if (h) {
                var idx = t.indexOf(h[0]) + h[0].length;
                ctx.replace(idx, idx, '\n\n' + markup);
            } else {
                ctx.replace(0, 0, t ? markup + '\n\n' : markup);
            }
        }
    }

    function fetchMovie(key, title, year) {
        var url = 'https://www.omdbapi.com/?apikey=' + encodeURIComponent(key) +
                  '&type=movie&t=' + encodeURIComponent(title);
        if (year) url += '&y=' + encodeURIComponent(year);
        return fetch(url).then(function (r) { return r.json(); });
    }

    function showMessage(title, msg) {
        openModal({ title: title, body: msg, confirm: { label: 'OK' } });
    }

    function promptForKey(rejected, onSaved) {
        var body = document.createDocumentFragment();

        if (rejected) {
            var notice = document.createElement('p');
            notice.textContent = 'The previously stored key was rejected by OMDb.';
            body.appendChild(notice);
        }

        var info = document.createElement('p');
        info.appendChild(document.createTextNode('Enter your OMDb API key. Get one at '));
        var link = document.createElement('a');
        link.href = 'https://www.omdbapi.com/apikey.aspx';
        link.target = '_blank';
        link.rel = 'noopener';
        link.textContent = 'omdbapi.com/apikey.aspx';
        info.appendChild(link);
        info.appendChild(document.createTextNode('.'));
        body.appendChild(info);

        var input = document.createElement('input');
        input.type = 'text';
        input.className = 'input';
        input.placeholder = 'OMDb API key';
        body.appendChild(input);

        openModal({
            title: 'OMDb API key required',
            body: body,
            confirm: {
                label: 'SAVE',
                onConfirm: function () {
                    var key = input.value.trim();
                    if (!key) return;
                    localStorage.setItem(STORAGE_KEY, key);
                    closeModal();
                    onSaved(key);
                },
            },
        });
    }

    function importWithKey(ctx, key, initialTitle) {
        var input = document.createElement('input');
        input.type = 'text';
        input.className = 'input';
        input.placeholder = 'Title, optionally with (YYYY)';
        input.value = initialTitle;

        openModal({
            title: 'Import movie',
            body: input,
            confirm: {
                label: 'IMPORT',
                onConfirm: function () {
                    var raw = input.value.trim();
                    if (!raw) return;
                    var parsed = parseTitleYear(raw);
                    closeModal();
                    fetchMovie(key, parsed.title, parsed.year)
                        .then(function (data) {
                            if (data && data.Response === 'False' &&
                                data.Error === 'Invalid API key!') {
                                localStorage.removeItem(STORAGE_KEY);
                                promptForKey(true, function (newKey) {
                                    importWithKey(ctx, newKey, raw);
                                });
                                return;
                            }
                            if (!data || data.Response === 'False') {
                                showMessage('Not found',
                                    (data && data.Error) || 'Movie not found.');
                                return;
                            }
                            insertOrReplace(ctx, buildBlock(data));
                        })
                        .catch(function () {
                            showMessage('Import failed', 'OMDb lookup failed.');
                        });
                },
            },
        });
    }

    function run(ctx) {
        var initialTitle = firstHeading(ctx.getValue() || '');
        var key = localStorage.getItem(STORAGE_KEY);
        if (!key) {
            promptForKey(false, function (newKey) {
                importWithKey(ctx, newKey, initialTitle);
            });
            return;
        }
        importWithKey(ctx, key, initialTitle);
    }

    return { run: run };
})();
