import Gtk from 'gi://Gtk'
import Gio from 'gi://Gio'
import GObject from 'gi://GObject'
import WebKit from 'gi://WebKit'
import Gdk from 'gi://Gdk'
import { gettext as _ } from 'gettext'

import * as utils from './utils.js'
import { WebView } from './webview.js'
import { locales, matchLocales } from './format.js'

const getLanguage = lang => {
    try {
        return new Intl.Locale(lang).language
    } catch (e) {
        console.warn(e)
        return 'en'
    }
}

const getGoogleTranslateLanguages = utils.memoize(() => {
    // list of languages supported by Google Translate
    // generated by running the following on https://cloud.google.com/translate/docs/languages
    // [...document.querySelector('table').querySelectorAll('tr')].map(tr => tr.querySelector('code')?.innerText).filter(x => x).map(x => `'${x}'`).join(', ')
    const displayName = new Intl.DisplayNames(locales, { type: 'language' })
    const langs = ['af', 'sq', 'am', 'ar', 'hy', 'as', 'ay', 'az', 'bm', 'eu', 'be', 'bn', 'bho', 'bs', 'bg', 'ca', 'ceb', 'zh-CN', 'zh-TW', 'co', 'hr', 'cs', 'da', 'dv', 'doi', 'nl', 'en', 'eo', 'et', 'ee', 'fil', 'fi', 'fr', 'fy', 'gl', 'ka', 'de', 'el', 'gn', 'gu', 'ht', 'ha', 'haw', 'he', 'hi', 'hmn', 'hu', 'is', 'ig', 'ilo', 'id', 'ga', 'it', 'ja', 'jv', 'kn', 'kk', 'km', 'rw', 'gom', 'ko', 'kri', 'ku', 'ckb', 'ky', 'lo', 'la', 'lv', 'ln', 'lt', 'lg', 'lb', 'mk', 'mai', 'mg', 'ms', 'ml', 'mt', 'mi', 'mr', 'mni-Mtei', 'lus', 'mn', 'my', 'ne', 'no', 'ny', 'or', 'om', 'ps', 'fa', 'pl', 'pt', 'pa', 'qu', 'ro', 'ru', 'sm', 'sa', 'gd', 'nso', 'sr', 'st', 'sn', 'sd', 'si', 'sk', 'sl', 'so', 'es', 'su', 'sw', 'sv', 'tl', 'tg', 'ta', 'tt', 'te', 'th', 'ti', 'ts', 'tr', 'tk', 'ak', 'uk', 'ur', 'ug', 'uz', 'vi', 'cy', 'xh', 'yi', 'yo', 'zu']
    const defaultLang = matchLocales(langs)[0] ?? 'en'
    return [langs.map(lang => [lang, displayName.of(lang)]), defaultLang]
})

const tools = {
    'dictionary': {
        label: _('Dictionary'),
        uri: 'foliate-selection-tool:///selection-tools/wiktionary.html',
        run: (__, { text, lang }) => ({
            msg: {
                footer: _('From <a id="link">Wiktionary</a>, released under the <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA License</a>.'),
                error: _('No Definitions Found'),
                errorAction: _('Search on Wiktionary'),
            },
            text,
            lang: getLanguage(lang),
        }),
    },
    'wikipedia': {
        label: _('Wikipedia'),
        uri: 'foliate-selection-tool:///selection-tools/wikipedia.html',
        run: (__, { text, lang }) => ({
            msg: {
                footer: _('From <a id="link">Wikipedia</a>, released under the <a href="https://en.wikipedia.org/wiki/Wikipedia:Text_of_the_Creative_Commons_Attribution-ShareAlike_4.0_International_License">CC BY-SA License</a>.'),
                error: _('No Definitions Found'),
                errorAction: _('Search on Wikipedia'),
            },
            text,
            lang: getLanguage(lang),
        }),
    },
    'translate': {
        label: _('Translate'),
        uri: 'foliate-selection-tool:///selection-tools/translate.html',
        run: (popover, { text }) => {
            const [langs, defaultLang] = getGoogleTranslateLanguages()
            return {
                msg: {
                    footer: _('Translation by Google Translate'),
                    error: _('Cannot retrieve translation'),
                    search: _('Search…'),
                    langs,
                },
                text,
                lang: popover.translate_target_language || defaultLang,
            }
        },
    },
}

const SelectionToolPopover = GObject.registerClass({
    GTypeName: 'FoliateSelectionToolPopover',
    Properties: utils.makeParams({
        'translate-target-language': 'string',
    }),
}, class extends Gtk.Popover {
    #webView = utils.connect(new WebView({
        settings: new WebKit.Settings({
            enable_write_console_messages_to_stdout: true,
            enable_back_forward_navigation_gestures: false,
            enable_hyperlink_auditing: false,
            enable_html5_database: false,
            enable_html5_local_storage: false,
        }),
    }), {
        'decide-policy': (_, decision, type) => {
            switch (type) {
                case WebKit.PolicyDecisionType.NAVIGATION_ACTION:
                case WebKit.PolicyDecisionType.NEW_WINDOW_ACTION: {
                    const { uri } = decision.navigation_action.get_request()
                    if (!uri.startsWith('foliate-selection-tool:')) {
                        decision.ignore()
                        new Gtk.UriLauncher({ uri }).launch(this.root, null, null)
                        return true
                    }
                }
            }
        },
    })
    constructor(params) {
        super(params)
        utils.bindSettings('viewer', this, ['translate-target-language'])
        Object.assign(this, {
            width_request: 300,
            height_request: 300,
        })
        this.child = this.#webView
        this.#webView.set_background_color(new Gdk.RGBA())
        this.#webView.registerHandler('settings', payload => {
            if (payload.key === 'translate-target-language')
                this.translate_target_language = payload.value
        })
    }
    loadTool(tool, init) {
        this.#webView.loadURI(tool.uri)
            .then(() => this.#webView.opacity = 1)
            .then(() => this.#webView.exec('init', init))
            .catch(e => console.error(e))
    }
})

const getSelectionToolPopover = utils.memoize(() => new SelectionToolPopover())

export const SelectionPopover = GObject.registerClass({
    GTypeName: 'FoliateSelectionPopover',
    Template: pkg.moduleuri('ui/selection-popover.ui'),
    Signals: {
        'show-popover': { param_types: [Gtk.Popover.$gtype] },
        'run-tool': { return_type: GObject.TYPE_JSOBJECT },
    },
}, class extends Gtk.PopoverMenu {
    constructor(params) {
        super(params)
        const model = this.menu_model
        const section = new Gio.Menu()
        model.insert_section(1, null, section)

        const group = new Gio.SimpleActionGroup()
        this.insert_action_group('selection-tools', group)

        for (const [name, tool] of Object.entries(tools)) {
            const action = new Gio.SimpleAction({ name })
            action.connect('activate', () => {
                const popover = getSelectionToolPopover()
                Promise.resolve(tool.run(popover, this.emit('run-tool')))
                    .then(x => popover.loadTool(tool, x))
                    .catch(e => console.error(e))
                this.emit('show-popover', popover)
            })
            group.add_action(action)
            section.append(tool.label, `selection-tools.${name}`)
        }
    }
})
