# Copyright (C) 2025 James Brotosky, Brandon Wickline
#
# This program 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.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

import logging
import logging.config
import logging.handlers
import os
from pathlib import Path
import platform

from dotenv import load_dotenv, set_key

from utils.configmanager import (
    get_system_value,
    load_system_config,
    load_user_config,
)


class TextualNotificationHandler(logging.Handler):
    """
    Custom logging handler that sends ERROR, WARNING, and CRITICAL logs
    to Textual toast notifications.
    """

    def __init__(self, app):
        super().__init__()
        self.app = app

    def emit(self, record):
        try:
            # Only handle ERROR, WARNING, and CRITICAL
            if record.levelno >= logging.WARNING:
                # Format the message
                msg = self.format(record)

                # Map log levels to Textual severity
                severity_map = {
                    logging.WARNING: "warning",
                    logging.ERROR: "error",
                    logging.CRITICAL: "error",
                }
                severity = severity_map.get(record.levelno, "information")

                # Send to Textual notification
                # Use call_from_thread if logging from non-main thread
                try:
                    self.app.notify(msg, severity=severity, timeout=5)
                except Exception:
                    # If we're not on the main thread, schedule it
                    try:
                        self.app.call_from_thread(
                            self.app.notify, msg, severity=severity, timeout=5
                        )
                    except Exception:
                        # Silently fail to avoid breaking the logging system
                        pass
        except Exception:
            # Silently fail to avoid breaking the logging system
            pass


def get_base_directory() -> Path:
    system = platform.system()
    home = Path.home()
    if system == "Windows":
        return Path(os.getenv("APPDATA", home / "AppData" / "Roaming")) / "Loxide"
    elif system == "Darwin":
        return home / "Library" / "Application Support" / "Loxide"
    else:
        return home / ".local" / "share" / "Loxide"


def configure_logging(log_dir: Path, log_level: str = "INFO"):
    log_file = log_dir / "Loxide.log"

    config = {
        "version": 1,
        "disable_existing_loggers": False,
        "formatters": {
            "detailed": {
                "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            },
            "simple": {"format": "%(levelname)s - %(message)s"},
            "toast": {"format": "%(name)s: %(message)s"},  # Simpler format for toasts
        },
        "handlers": {
            "file": {
                "class": "logging.handlers.TimedRotatingFileHandler",
                "filename": str(log_file),
                "when": "midnight",
                "interval": 1,
                "backupCount": 7,
                "encoding": "utf-8",
                "level": "DEBUG",
                "formatter": "detailed",
            },
            # REMOVED console handler - it interferes with Textual TUI
        },
        "root": {
            "level": "DEBUG",
            "handlers": ["file"],  # Only use file handler, not console
        },
    }

    # Add Windows Event Log handler if on Windows
    if platform.system() == "Windows":
        try:
            config["handlers"]["eventlog"] = {
                "class": "logging.handlers.NTEventLogHandler",
                "appname": "Loxide",  # Event log source name
                "level": "CRITICAL",  # Only log critical errors
                "formatter": "simple",  # Use simple format
            }
            config["root"]["handlers"].append("eventlog")
        except Exception as e:
            logging.warning(f"Could not attach Windows Event Log handler: {e}")

    # Apply the logging configuration
    logging.config.dictConfig(config)
    logging.getLogger().debug("✅ Logging configured.")

    # Return a function to attach the notification handler once the app is created
    def attach_notification_handler(app):
        """Attach the Textual notification handler to the root logger."""
        handler = TextualNotificationHandler(app)
        handler.setLevel(logging.WARNING)  # Only WARNING and above
        formatter = logging.Formatter("%(name)s: %(message)s")
        handler.setFormatter(formatter)
        logging.getLogger().addHandler(handler)
        logging.getLogger().debug("✅ Textual notification handler attached.")

    return attach_notification_handler


def setup():
    """
    Initialize the application environment:
    1. Create directory structure
    2. Load system config (immutable, from system_config.json)
    3. Load user config (mutable, from user_config.json)
    4. Configure logging
    5. Set up .env with WORKING_DIR only

    Returns:
        attach_notification_handler: Function to attach notification handler to TUI app
    """
    base_dir = get_base_directory()
    dirs = {
        "config": base_dir / "config",
        "cache": base_dir / "cache",
        "logs": base_dir / "logs",
    }

    for name, path in dirs.items():
        path.mkdir(parents=True, exist_ok=True)
        logging.debug(f"{name.capitalize()} directory ensured at: {path}")

    # Load system config (immutable)
    load_system_config()

    # Configure logging with system-defined log level
    log_level = get_system_value("LOG_LEVEL", str, "INFO")
    attach_handler = configure_logging(dirs["logs"], log_level)

    # Load user config (mutable)
    load_user_config(dirs["config"])

    # Set up .env file - ONLY for WORKING_DIR (runtime-configurable value)
    env_path = base_dir / ".env"
    if not env_path.exists():
        env_path.touch()
    load_dotenv(dotenv_path=env_path, override=True)

    # Set up working directory (only dynamic value in .env)
    working_dir = Path(os.getenv("WORKING_DIR") or (base_dir / "data"))
    working_dir.mkdir(parents=True, exist_ok=True)
    set_key(str(env_path), "WORKING_DIR", str(working_dir))
    os.environ["WORKING_DIR"] = str(working_dir)
    logging.debug(f"Working directory set to: {working_dir}")

    # Create folder structure in working directory
    folders_structure = {
        "Approved": [],
        "Needs_Review": ["Review_First", "Review_Second", "HTML"],
        "Preflight": ["HTML"],
    }

    for folder_name, subfolders in folders_structure.items():
        folder_path = working_dir / folder_name
        folder_path.mkdir(parents=True, exist_ok=True)
        logging.debug(f"'{folder_name}' folder ensured at: {folder_path}")
        for subfolder in subfolders:
            subfolder_path = folder_path / subfolder
            subfolder_path.mkdir(parents=True, exist_ok=True)
            logging.debug(f"'{subfolder}' subfolder created at: {subfolder_path}")

    logging.info("✅ Setup complete")

    # Return the attach handler function
    return attach_handler
