"""Изменяет цветовую тему приложения и иконку

"color_theme": {
  "enabled": true,
  "logo": {
    "gradient": {
      "angle": 0.0,
      "start_color": "#ffccff00",
      "end_color": "#ffcccc00"
    },
    "ears_color": "#ffffd0d0"
  },
  "colors": {
    "primary": "#ccff00",
    "secondary": "#ffcccc00",
    "background": "#ffffff",
    "text": "#000000"
  }
}
"""

__author__ = "wowlikon <wowlikon@gmail.com>"
__version__ = "1.0.0"
from typing import Any, Dict

from lxml import etree
from pydantic import BaseModel, Field, model_validator

from utils.config import PatchTemplate
from utils.public import change_color, insert_after_color, insert_after_public


class Gradient(BaseModel):
    priority: int = Field(frozen=True, exclude=True, default=0)
    angle: float = Field(0.0, description="Угол градиента")
    start_color: str = Field("#ffccff00", description="Начальный цвет градиента")
    end_color: str = Field("#ffcccc00", description="Конечный цвет градиента")


class Logo(BaseModel):
    gradient: Gradient = Field(
        default_factory=Gradient, description="Настройки градиента"
    )
    ears_color: str = Field("#ffd0d0d0", description="Цвет ушей логотипа")


class Colors(BaseModel):
    primary: str = Field("#ccff00", description="Основной цвет")
    secondary: str = Field("#ffcccc00", description="Вторичный цвет")
    background: str = Field("#ffffff", description="Фоновый цвет")
    text: str = Field("#000000", description="Цвет текста")


class Patch(PatchTemplate):
    priority: int = Field(frozen=True, exclude=True, default=0)
    logo: Logo = Field(default_factory=Logo, description="Настройки цветов логотипа")
    colors: Colors = Field(default_factory=Colors, description="Настройки цветов")

    @model_validator(mode="before")
    @classmethod
    def validate_nested(cls, data):
        if isinstance(data, dict):
            if "logo" in data and isinstance(data["logo"], dict):
                data["logo"] = Logo(**data["logo"])
            if "colors" in data and isinstance(data["colors"], dict):
                data["colors"] = Colors(**data["colors"])
        return data

    def hex_to_lottie(hex_color: str) -> tuple[float, float, float]:
        hex_color = hex_color.lstrip("#")
        hex_color = hex_color[2:] if len(hex_color) == 8 else hex_color
        return (
            int(hex_color[:2], 16) / 255.0,
            int(hex_color[2:4], 16) / 255.0,
            int(hex_color[4:6], 16) / 255.0,
        )

    def apply(self, base: Dict[str, Any]) -> bool:
        main_color = self.colors.primary
        splash_color = self.colors.secondary

        # Обновление сообщения об отсутствии подключения
        with open(
            "./decompiled/assets/no_connection.html", "r", encoding="utf-8"
        ) as file:
            file_contents = file.read()

        new_contents = file_contents.replace("#f04e4e", main_color)

        with open(
            "./decompiled/assets/no_connection.html", "w", encoding="utf-8"
        ) as file:
            file.write(new_contents)

        # Суффиксы лого
        drawable_types = ["", "-night"]

        for drawable_type in drawable_types:
            # Градиент лого приложения
            file_path = f"./decompiled/res/drawable{drawable_type}/$logo__0.xml"

            parser = etree.XMLParser(remove_blank_text=True)
            tree = etree.parse(file_path, parser)
            root = tree.getroot()

            # Замена атрибутов значениями из конфигурации
            root.set(
                f"{{{base['xml_ns']['android']}}}angle", str(self.logo.gradient.angle)
            )
            root.set(
                f"{{{base['xml_ns']['android']}}}startColor",
                self.logo.gradient.start_color,
            )
            root.set(
                f"{{{base['xml_ns']['android']}}}endColor", self.logo.gradient.end_color
            )

            # Сохранение
            tree.write(
                file_path, pretty_print=True, xml_declaration=True, encoding="utf-8"
            )

            # Замена анимации лого
            file_path = (
                f"./decompiled/res/drawable{drawable_type}/$logo_splash_anim__0.xml"
            )

            parser = etree.XMLParser(remove_blank_text=True)
            tree = etree.parse(file_path, parser)
            root = tree.getroot()

            for el in root.findall("path", namespaces=base["xml_ns"]):
                name = el.get(f"{{{base['xml_ns']['android']}}}name")
                if name == "path":
                    el.set(
                        f"{{{base['xml_ns']['android']}}}fillColor",
                        self.colors.secondary,
                    )
                elif name in ["path_1", "path_2"]:
                    el.set(
                        f"{{{base['xml_ns']['android']}}}fillColor",
                        self.logo.ears_color,
                    )

            # Сохранение
            tree.write(
                file_path, pretty_print=True, xml_declaration=True, encoding="utf-8"
            )

        for filename in ["$ic_launcher_foreground__0", "$ic_banner_foreground__0"]:
            file_path = f"./decompiled/res/drawable-v24/{filename}.xml"

            parser = etree.XMLParser(remove_blank_text=True)
            tree = etree.parse(file_path, parser)
            root = tree.getroot()

            # Замена атрибутов значениями из конфигурации
            root.set(
                f"{{{base['xml_ns']['android']}}}angle", str(self.logo.gradient.angle)
            )
            items = root.findall("item", namespaces=base["xml_ns"])
            assert len(items) == 2
            items[0].set(
                f"{{{base['xml_ns']['android']}}}color", self.logo.gradient.start_color
            )
            items[1].set(
                f"{{{base['xml_ns']['android']}}}color", self.logo.gradient.end_color
            )

            # Сохранение
            tree.write(
                file_path, pretty_print=True, xml_declaration=True, encoding="utf-8"
            )

        # Добаление новых цветов для темы
        insert_after_public("carmine", "custom_color")
        insert_after_public("carmine_alpha_10", "custom_color_alpha_10")
        insert_after_color(
            "carmine", "custom_color", main_color[0] + "ff" + main_color[1:]
        )
        insert_after_color(
            "carmine_alpha_10",
            "custom_color_alpha_10",
            main_color[0] + "1a" + main_color[1:],
        )

        # Замена цветов
        change_color("accent_alpha_10", main_color[0] + "1a" + main_color[1:])
        change_color("accent_alpha_20", main_color[0] + "33" + main_color[1:])
        change_color("accent_alpha_50", main_color[0] + "80" + main_color[1:])
        change_color("accent_alpha_70", main_color[0] + "b3" + main_color[1:])

        change_color("colorAccent", main_color[0] + "ff" + main_color[1:])
        change_color("link_color", main_color[0] + "ff" + main_color[1:])
        change_color("link_color_alpha_70", main_color[0] + "b3" + main_color[1:])
        change_color("refresh_progress", main_color[0] + "ff" + main_color[1:])

        change_color("ic_launcher_background", "#ff000000")
        change_color("bottom_nav_indicator_active", "#ffffffff")
        change_color(
            "bottom_nav_indicator_icon_checked", main_color[0] + "ff" + main_color[1:]
        )
        change_color(
            "bottom_nav_indicator_label_checked", main_color[0] + "ff" + main_color[1:]
        )

        return True
