#
#   Copyright © 2021,2022 IsardVDI S.L.
#
#   This file is part of DD
#
#   DD is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or (at your
#   option) any later version.
#
#   DD 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 Affero General Public License for more
#   details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with DD. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later

import json
import logging
import os.path
import pprint
import time
import traceback
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Dict

import yaml
from jinja2 import Environment, FileSystemLoader

if TYPE_CHECKING:
    from api.flaskapp import ApiFlaskApp


def write_css(app: "ApiFlaskApp") -> None:
    env = Environment(loader=FileSystemLoader("api/static/_templates"))
    css_template = env.get_template("dd.css")
    with open("menu/custom.yaml", "r") as menu_custom_file:
        menu_custom_yaml = menu_custom_file.read()
    menu_custom = yaml.full_load(menu_custom_yaml)
    # Add custom CSS from operator
    menu_custom["custom_css"] = ""
    custom_css_file = "/custom/css/custom.css"
    if os.path.isfile(custom_css_file):
        menu_custom["custom_css"] = (
            open(custom_css_file).read().replace("DOMAIN", app.config["DOMAIN"])
        )
    css = css_template.render(data=menu_custom)
    with open("api/static/css/dd.css", "w") as css_file:
        css_file.write(css)


class Menu:
    app: "ApiFlaskApp"

    def __init__(self, app: "ApiFlaskApp") -> None:
        self.app = app
        # self.user_menudict=self.gen_user_menu()
        # pprint.pprint(self.user_menudict)
        # self.write_user_menu()

        self.menudict = self.gen_header()
        pprint.pprint(self.menudict)
        self.write_headers()
        write_css(app)

    def patch_url(self, subdomain_part: str, domain: str, url: str) -> str:
        """
        Patch a URL only if it is a relative URL, so it conforms to:
        https://[{subdomain}.]{domain}{url}
        """
        # Only modify if it is a relative URL
        if not url or url.startswith("/") or url.startswith("#"):
            # Ensure subdomain doesn't have leading dots
            subdomain_part = subdomain_part.lstrip(".")
            # Ensure the subdomain ends with a trailing dot
            if subdomain_part and not subdomain_part.endswith("."):
                subdomain_part = f"{subdomain_part}."
            # Actually construct the full URL
            url = "".join(
                [
                    "https://",
                    subdomain_part,
                    domain,
                    url,
                ]
            )
        return url

    """ HEADER & APP MENU """

    def gen_header(self) -> Dict:
        domain = self.app.config["DOMAIN"]
        with open(r"menu/system.yaml") as yml:
            system = yaml.load(yml, Loader=yaml.FullLoader)

        user_menu = []
        for item in system["user_menu"]:
            # We pop 'subdomain' so it is not in user_menu
            item["href"] = self.patch_url(
                item.pop("subdomain", ""), domain, item["href"]
            )
            user_menu.append(item)

        apps_internal = []
        for app in system.get("apps_internal", []):
            app_href = app["href"] if app.get("href", "") else "/"
            # We pop 'subdomain' so it is not in apps_internal
            app["href"] = self.patch_url(app.pop("subdomain", ""), domain, app_href)
            apps_internal.append(app)

        with open(r"menu/custom.yaml") as yml:
            custom = yaml.load(yml, Loader=yaml.FullLoader)
        custom["background_login"] = self.patch_url(
            "api", domain, custom.get("background_login", "/img/background.png")
        )
        custom["logo"] = self.patch_url(
            "api", domain, custom.get("logo", "/img/logo.png")
        )
        custom["product_logo"] = self.patch_url(
            "api", domain, custom.get("product_logo", "/img/product-logo.svg")
        )

        menudict: Dict = custom
        menudict["user"] = {
            "account": self.patch_url(
                "sso", domain, system.get("user", {}).get("account", "")
            ),
            "avatar": self.patch_url(
                "sso", domain, system.get("user", {}).get("avatar", "")
            ),
        }
        menudict.update(
            {
                "apps_internal": apps_internal,
                "user_menu": user_menu,
                "user_avatar": menudict["user"]["avatar"],
            }
        )
        return menudict

    def write_headers(self) -> None:
        env = Environment(loader=FileSystemLoader("api/static/_templates"))

        template = env.get_template("user_menu.html")
        output_from_parsed_template = template.render(data=self.menudict)
        print(output_from_parsed_template)
        with open("api/static/templates/user_menu_header.html", "w") as fh:
            fh.write(output_from_parsed_template)

        # with open("api/static/templates/user_menu_header.json", "w") as fh:
        #     fh.write(json.dumps(self.menudict))

        template = env.get_template("apps_menu.html")
        output_from_parsed_template = template.render(data=self.menudict)
        print(output_from_parsed_template)
        with open("api/static/templates/header.html", "w") as fh:
            fh.write(output_from_parsed_template)

        ## Nextcloud. Nginx will serve /header/html/nextcloud -> header_nextcloud.html
        with open("api/static/templates/header_nextcloud.html", "w") as fh:
            fh.write(output_from_parsed_template)
        with open("api/static/templates/header_nextcloud.html", "a") as fh:
            with open("api/static/_templates/nextcloud.html", "r") as nextcloud:
                fh.write(nextcloud.read())
        with open("api/static/templates/header.json", "w") as fh:
            fh.write(json.dumps(self.menudict))

        ## Admin app. Nginx will serve /header/html/admin -> header_admin.html
        template = env.get_template("admin.html")
        output_from_parsed_template = template.render(data=self.menudict)
        print(output_from_parsed_template)
        with open("api/static/templates/header_admin.html", "w") as fh:
            fh.write(output_from_parsed_template)

        ## SSO app. Nginx will serve /header/html/sso -> header_sso.html
        template = env.get_template("sso.html")
        output_from_parsed_template = template.render(data=self.menudict)
        print(output_from_parsed_template)
        with open("api/static/templates/header_sso.html", "w") as fh:
            fh.write(output_from_parsed_template)

    def get_header(self) -> Dict:
        return self.menudict
        # with open('menu.yaml', 'w') as yml:
        #     print(yaml.dump(header, yml, allow_unicode=True))
