# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
import platform
from dataclasses import dataclass
from sys import float_info
from typing import Optional

import bpy
from bpy.app.translations import pgettext

from .blender_manifest import BlenderManifest
from .logger import get_logger

logger = get_logger(__name__)


@dataclass
class Cache:
    use: bool
    last_blender_restart_required: bool
    last_blender_manifest_modification_time: float
    initial_blender_manifest_content: bytes


cache = Cache(
    use=False,
    last_blender_restart_required=False,
    last_blender_manifest_modification_time=0.0,
    initial_blender_manifest_content=BlenderManifest.default_blender_manifest_path().read_bytes(),
)


def clear_addon_version_cache() -> Optional[float]:
    cache.use = False
    return None


def trigger_clear_addon_version_cache() -> None:
    if tuple(bpy.app.version) >= (4, 2):
        return
    if bpy.app.timers.is_registered(clear_addon_version_cache):
        return
    bpy.app.timers.register(clear_addon_version_cache, first_interval=0.5)


def min_unsupported_blender_major_minor_version() -> Optional[tuple[int, int]]:
    blender_version_max = BlenderManifest.read().blender_version_max
    if blender_version_max is None:
        return None
    return (blender_version_max[0], blender_version_max[1])


def get_addon_version() -> tuple[int, int, int]:
    return BlenderManifest.read().version


def blender_restart_required() -> bool:
    if tuple(bpy.app.version) >= (4, 2):
        return False

    if cache.use:
        return cache.last_blender_restart_required

    cache.use = True

    if cache.last_blender_restart_required:
        return True

    blender_manifest_path = BlenderManifest.default_blender_manifest_path()
    blender_manifest_modification_time = blender_manifest_path.stat().st_mtime
    if (
        abs(
            cache.last_blender_manifest_modification_time
            - blender_manifest_modification_time
        )
        < float_info.epsilon
    ):
        return False

    cache.last_blender_manifest_modification_time = blender_manifest_modification_time

    blender_manifest_content = blender_manifest_path.read_bytes()
    if blender_manifest_content == cache.initial_blender_manifest_content:
        return False

    cache.last_blender_restart_required = True
    return True


def stable_release() -> bool:
    if bpy.app.version_cycle == "release":
        return True

    # Microsoft Store distributes RC versions of 3.3.11 and 3.6.3 as
    # release versions.
    return platform.system() == "Windows" and bpy.app.version_cycle == "rc"


def supported() -> bool:
    v = min_unsupported_blender_major_minor_version()
    if v is None:
        return True
    return bpy.app.version[:2] < v


def preferences_warning_message() -> Optional[str]:
    if blender_restart_required():
        return pgettext(
            "The VRM add-on has been updated."
            + " Please restart Blender to apply the changes."
        )
    if not stable_release():
        return pgettext(
            "VRM add-on is not compatible with Blender {blender_version_cycle}."
        ).format(blender_version_cycle=bpy.app.version_cycle.capitalize())
    if not supported():
        return pgettext(
            "The installed VRM add-on is not compatible with Blender {blender_version}."
            + " Please upgrade the add-on.",
        ).format(blender_version=".".join(map(str, bpy.app.version[:2])))
    return None


def panel_warning_message() -> Optional[str]:
    if blender_restart_required():
        return pgettext(
            "The VRM add-on has been\n"
            + "updated. Please restart Blender\n"
            + "to apply the changes."
        )
    if not stable_release():
        return pgettext(
            "VRM add-on is\n"
            + "not compatible with\n"
            + "Blender {blender_version_cycle}."
        ).format(blender_version_cycle=bpy.app.version_cycle.capitalize())
    if not supported():
        return pgettext(
            "The installed VRM add-\n"
            + "on is not compatible with\n"
            + "Blender {blender_version}. Please update."
        ).format(blender_version=".".join(map(str, bpy.app.version[:2])))
    return None


def validation_warning_message() -> Optional[str]:
    if blender_restart_required():
        return pgettext(
            "The VRM add-on has been updated."
            + " Please restart Blender to apply the changes."
        )
    if not stable_release():
        return pgettext(
            "VRM add-on is not compatible with Blender {blender_version_cycle}."
            + " The VRM may not be exported correctly.",
        ).format(blender_version_cycle=bpy.app.version_cycle.capitalize())
    if not supported():
        return pgettext(
            "The installed VRM add-on is not compatible with Blender {blender_version}."
            + " The VRM may not be exported correctly."
        ).format(blender_version=".".join(map(str, bpy.app.version)))
    return None
