# Copyright 2021 Vincent Texier <vit@free.fr>
#
# This software is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import logging
import sys
from collections import OrderedDict
from datetime import datetime
from typing import Optional

from PyQt5.QtCore import QLocale
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QWidget

from tikka.domains.application import Application
from tikka.domains.entities.account import Account, AccountCryptoType
from tikka.domains.entities.constants import TEST_DATA_PATH
from tikka.domains.entities.profile import Profile
from tikka.slots.pyqt.entities.event_bus import EventBus
from tikka.slots.pyqt.entities.worker import ThreadManager
from tikka.slots.pyqt.resources.gui.widgets.account_profile_rc import (
    Ui_AccountProfileWidget,
)
from tikka.slots.pyqt.widgets.account_tabs.profile_html_dom import ProfileHTMLDOM
from tikka.slots.pyqt.windows.profile_change_account import ProfileChangeAccountWindow


class AccountProfileWidget(QWidget, Ui_AccountProfileWidget):
    """
    AccountProfileWidget class
    """

    def __init__(
        self,
        application: Application,
        account: Account,
        parent: Optional[QWidget] = None,
    ) -> None:
        """
        Init AccountProfileWidget instance

        :param application: Application instance
        :param account: Account instance
        :param parent: QWidget instance
        """
        super().__init__(parent=parent)
        self.setupUi(self)

        self.application = application
        self._ = self.application.translator.gettext

        self.event_bus = EventBus.instance()

        self.account: Account = account

        self.profile: Optional[Profile] = self.application.profiles.get(
            self.account.address
        )

        # profile webview
        self.profile_web_view = QWebEngineView(self)
        self.profileWebViewFrame.layout().addWidget(self.profile_web_view)
        self.profile_web_view.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Expanding
        )
        # Intercepter les changements d'URL pour ouvrir les liens externes
        self.profile_web_view.urlChanged.connect(self.on_profile_web_view_url_changed)

        ##############################
        # ASYNC METHODS
        ##############################
        self.thread_manager: ThreadManager = ThreadManager(self)

        # events
        self.profileChangeAccountButton.clicked.connect(
            self.on_profile_change_account_button_clicked
        )

        self.update_ui()

    def cleanup(self):
        """
        Clean up WebEngine resources

        Fix message: Release of profile requested but WebEnginePage still not deleted. Expect troubles !

        :return:
        """
        if hasattr(self, "profile_web_view"):
            # Clear the profile web view
            self.profile_web_view.deleteLater()
            del self.profile_web_view

    def closeEvent(self, event):
        """
        Triggered when user close main window or tab

        :param event:
        :return:
        """
        self.cleanup()
        super().closeEvent(event)

    def async_refresh_data_from_network(self):
        """
        Triggered when user click on account tab refresh button

        :return:
        """
        self.thread_manager.start(
            self.fetch_profile_from_network,
            self._on_finished_fetch_profile_from_network,
        )

    def fetch_profile_from_network(self):
        """
        Get last account data from the network

        :return:
        """
        if not self.application.connections.datapod.is_connected():
            return

        try:
            self.profile = self.application.profiles.network_update(self.account)
        except Exception as exception:
            logging.exception(exception)

    def _on_finished_fetch_profile_from_network(self):
        """
        Triggered when async request fetch_account_from_network is finished

        :return:
        """
        self.update_ui()
        logging.debug("Account profile widget update")

    def update_ui(self):
        """
        Update UI from self.account

        :return:
        """
        # update local data from DB
        self.account = self.application.accounts.get_by_address(self.account.address)
        self.profile = self.application.profiles.get(self.account.address)

        if self.profile is not None:
            self.profile_web_view.setHtml(self.get_profile_as_html())

        self.profileChangeAccountButton.setEnabled(
            self.application.connections.node.is_connected()
            and self.application.wallets.exists(self.account.address)
        )

    def get_profile_as_html(self) -> str:
        """
        Display profile data as HTML in web view

        :return:
        """
        if self.profile is not None:
            updated_on_time_stamp = self.profile.data.get("time", 0)
            updated_on_localized_datetime_string = self.locale().toString(
                datetime.fromtimestamp(updated_on_time_stamp),
                QLocale.dateTimeFormat(self.locale(), QLocale.ShortFormat),
            )
            updated_on_localized_string = self._(
                "Updated at {localized_string}"
            ).format(localized_string=updated_on_localized_datetime_string)

            return ProfileHTMLDOM(
                self.profile.data, updated_on_localized_string
            ).get_html()

        return self._("No profile.")

    def on_profile_web_view_url_changed(self, url):
        """
        Triggered when user click on web link in profile web view

        :return:
        """
        if url.isValid() and url.scheme() in ["http", "https"]:
            QDesktopServices.openUrl(url)
            # Reload page to stay on original content
            self.profile_web_view.sender().setHtml(self.get_profile_as_html())

    def on_profile_change_account_button_clicked(self):
        """
        Triggered when user click on identity change account button

        :return:
        """
        if self.profile is not None:
            window = ProfileChangeAccountWindow(self.application, self.account)
            window.exec_()


if __name__ == "__main__":
    qapp = QApplication(sys.argv)

    application_ = Application(TEST_DATA_PATH)

    account_ = application_.accounts.create_new_root_account(
        mnemonic="bottom drive obey lake curtain smoke basket hold race lonely fit walk",
        language_code="en",
        crypto_type=AccountCryptoType.ED25519,
        name="Root ED",
        password="aaaaaa",
    )

    application_.profiles.add(
        Profile(
            account_.address,
            OrderedDict(
                {
                    "hash": "B321DCE30F60A1A977C8D2FBA50B16C9CE1B42D59C4908709F49923628188D4C",
                    "signature": "m9YxEpz6yZVgaFe4s5Hmk7M5qHWUDOHqZIOycJfQAM5ZpyzVxCMygVlCq9sdomRtfE/k7ynLxDuz2/ScLyHxBA==",
                    "version": 2,
                    "title": "alice",
                    "issuer": "4XDM51AWupjKLWkVPxxJxrqN8DEhmPuY3S1FEepvHvxN",
                    "time": 1771626386,
                    "description": "auieauieauie !!!!!!auieuieauie",
                    "avatar": {},
                }
            ),
        )
    )

    main_window = QMainWindow()
    main_window.show()

    main_window.setCentralWidget(
        AccountProfileWidget(application_, account_, main_window)
    )

    sys.exit(qapp.exec_())
