"""Shared utility functions for the medical exams parser."""

import json
import logging
import re
import sys
from pathlib import Path
from typing import Any
from PIL import Image, ImageEnhance
from dotenv import load_dotenv

# Prompts directory
PROMPTS_DIR = Path(__file__).parent.parent / "prompts"


def load_prompt(name: str) -> str:
    """Load a prompt from the prompts directory."""
    path = PROMPTS_DIR / f"{name}.md"
    if not path.exists():
        raise FileNotFoundError(f"Prompt file not found: {path}")
    return path.read_text(encoding="utf-8").strip()


def preprocess_page_image(image: Image.Image) -> Image.Image:
    """Convert image to grayscale, resize, and enhance contrast."""
    gray_image = image.convert("L")
    MAX_LONG_SIDE = 1000
    long_side = max(gray_image.width, gray_image.height)
    if long_side > MAX_LONG_SIDE:
        ratio = MAX_LONG_SIDE / long_side
        new_width = int(gray_image.width * ratio)
        new_height = int(gray_image.height * ratio)
        gray_image = gray_image.resize((new_width, new_height), Image.Resampling.LANCZOS)
    return ImageEnhance.Contrast(gray_image).enhance(2.0)


def strip_markdown_fences(text: str) -> str:
    """Remove markdown code fences from text."""
    if text.startswith("```"):
        lines = text.split("\n")
        if lines[0].startswith("```"):
            lines = lines[1:]
        if lines and lines[-1].strip() == "```":
            lines = lines[:-1]
        text = "\n".join(lines).strip()
    return text


def parse_llm_json_response(text: str, fallback: Any = None) -> Any:
    """Parse JSON from LLM response, handling markdown fences."""
    text = strip_markdown_fences(text)
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return fallback


def extract_dates_from_text(text: str) -> list[str]:
    """Extract all dates in YYYY-MM-DD format from text. Handles DD/MM/YYYY, DD-MM-YYYY, and YYYY-MM-DD."""
    dates = []
    for match in re.finditer(r"\b(\d{4})-(\d{2})-(\d{2})\b", text):
        year, month, day = match.groups()
        if 1900 <= int(year) <= 2100 and 1 <= int(month) <= 12 and 1 <= int(day) <= 31:
            dates.append(f"{year}-{month}-{day}")
    for match in re.finditer(r"\b(\d{1,2})[/-](\d{1,2})[/-](\d{4})\b", text):
        day, month, year = match.groups()
        day_int, month_int, year_int = int(day), int(month), int(year)
        if 1900 <= year_int <= 2100 and 1 <= month_int <= 12 and 1 <= day_int <= 31:
            dates.append(f"{year}-{month:0>2}-{day:0>2}")
    return dates


def load_dotenv_with_env() -> str | None:
    """
    Load environment variables with optional --env overlay.

    Parses --env flag from sys.argv before full argument parsing,
    loads base .env first, then overlays .env.{name} if specified.

    Returns:
        The env name if --env was specified, None otherwise.
    """
    # Parse --env flag early (before argparse)
    env_name = None
    for i, arg in enumerate(sys.argv):
        if arg == "--env" and i + 1 < len(sys.argv):
            env_name = sys.argv[i + 1]
            break
        elif arg.startswith("--env="):
            env_name = arg.split("=", 1)[1]
            break

    # Load environment file (standalone behavior)
    if env_name:
        # Only load .env.{name} when specified
        env_path = Path(f".env.{env_name}")
        if env_path.exists():
            load_dotenv(env_path)
        else:
            print(f"Warning: Environment file not found: {env_path}")
    else:
        # Load base .env when no env specified
        load_dotenv()

    # Always overlay .env.local if it exists (local overrides, standard convention)
    local_env_path = Path(".env.local")
    if local_env_path.exists():
        load_dotenv(local_env_path, override=True)

    return env_name


def setup_logging(log_dir: Path, clear_logs: bool = False) -> logging.Logger:
    """Configure file and console logging, optionally clearing existing logs."""
    log_dir.mkdir(exist_ok=True)
    info_log_path = log_dir / "info.log"
    error_log_path = log_dir / "error.log"

    if clear_logs:
        for log_file in (info_log_path, error_log_path):
            if log_file.exists():
                log_file.write_text("", encoding="utf-8")

    # Configure root logger so all modules inherit the same level
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.INFO)

    # Remove existing handlers from root logger
    for handler in list(root_logger.handlers):
        root_logger.removeHandler(handler)
        handler.close()

    # Formatters
    file_formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    console_formatter = logging.Formatter("%(levelname)s: %(message)s")

    # File handlers
    info_handler = logging.FileHandler(info_log_path, encoding="utf-8")
    info_handler.setLevel(logging.INFO)
    info_handler.setFormatter(file_formatter)

    error_handler = logging.FileHandler(error_log_path, encoding="utf-8")
    error_handler.setLevel(logging.ERROR)
    error_handler.setFormatter(file_formatter)

    # Console handler
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
    console_handler.setFormatter(console_formatter)

    root_logger.addHandler(info_handler)
    root_logger.addHandler(error_handler)
    root_logger.addHandler(console_handler)

    # Return a logger for the calling module
    logger = logging.getLogger(__name__)
    return logger
