"""
Storage service for manual health logs.

Handles reading/writing user-entered diet, alcohol, supplement, and feeling data.
"""

import json
from datetime import date, datetime
from pathlib import Path
from typing import Optional, List

from health import config
from health.models.manual_log import (
    DailyManualLog,
    DietEntry,
    AlcoholEntry,
    SupplementEntry,
    BodyFeelingEntry,
)
from health.utils.logging_config import setup_logger

logger = setup_logger(__name__)


class ManualLogStorage:
    """Service for storing and retrieving manual health logs."""

    def __init__(self, data_dir: Optional[Path] = None) -> None:
        """Initialize manual log storage service.

        Args:
            data_dir: Optional data directory path (defaults to config.DATA_DIR)
        """
        self.data_dir = data_dir or config.DATA_DIR
        self.manual_log_dir = self.data_dir / "manual_logs"
        self.manual_log_dir.mkdir(parents=True, exist_ok=True)

    def _get_file_path(self, target_date: date, create_dirs: bool = True) -> Path:
        """Get file path for a manual log.

        Args:
            target_date: Date of the log
            create_dirs: Whether to create directories if they don't exist

        Returns:
            Full path to JSON file (data/health/manual_logs/YYYY/MM/YYYY-MM-DD.json)
        """
        year = str(target_date.year)
        month = f"{target_date.month:02d}"
        filename = f"{target_date.isoformat()}.json"

        file_path = self.manual_log_dir / year / month / filename

        if create_dirs:
            file_path.parent.mkdir(parents=True, exist_ok=True)

        return file_path

    def load_log(self, target_date: date) -> DailyManualLog:
        """Load manual log for a specific date.

        Args:
            target_date: Date to load

        Returns:
            DailyManualLog instance (creates new if doesn't exist)
        """
        file_path = self._get_file_path(target_date, create_dirs=False)

        if not file_path.exists():
            # Return empty log for this date
            logger.debug(f"No manual log found for {target_date}, creating new")
            return DailyManualLog(log_date=target_date)

        try:
            with open(file_path, "r", encoding="utf-8") as f:
                data = json.load(f)

            log = DailyManualLog(**data)
            logger.debug(f"Loaded manual log for {target_date}")
            return log

        except Exception as e:
            logger.error(f"Failed to load manual log for {target_date}: {e}")
            # Return empty log on error
            return DailyManualLog(log_date=target_date)

    def save_log(self, log: DailyManualLog) -> Path:
        """Save manual log to JSON file.

        Args:
            log: DailyManualLog instance to save

        Returns:
            Path to saved file
        """
        try:
            # Update timestamp
            log.updated_at = datetime.now()

            file_path = self._get_file_path(log.log_date)

            # Convert to dict and save as JSON
            data_dict = log.model_dump(mode="json")

            with open(file_path, "w", encoding="utf-8") as f:
                json.dump(data_dict, f, indent=2, ensure_ascii=False)

            logger.info(f"Saved manual log for {log.log_date} to {file_path}")
            return file_path

        except Exception as e:
            logger.error(f"Failed to save manual log for {log.log_date}: {e}")
            raise

    def add_diet_entry(
        self, target_date: date, entry: DietEntry
    ) -> DailyManualLog:
        """Add a diet entry to the log.

        Args:
            target_date: Date of the entry
            entry: DietEntry to add

        Returns:
            Updated DailyManualLog
        """
        log = self.load_log(target_date)
        log.diet_entries.append(entry)
        self.save_log(log)
        logger.info(f"Added diet entry for {target_date} at {entry.time}")
        return log

    def add_alcohol_entry(
        self, target_date: date, entry: AlcoholEntry
    ) -> DailyManualLog:
        """Add an alcohol entry to the log.

        Args:
            target_date: Date of the entry
            entry: AlcoholEntry to add

        Returns:
            Updated DailyManualLog
        """
        log = self.load_log(target_date)
        log.alcohol_entries.append(entry)
        self.save_log(log)
        logger.info(f"Added alcohol entry for {target_date} at {entry.time}")
        return log

    def add_supplement_entry(
        self, target_date: date, entry: SupplementEntry
    ) -> DailyManualLog:
        """Add a supplement entry to the log.

        Args:
            target_date: Date of the entry
            entry: SupplementEntry to add

        Returns:
            Updated DailyManualLog
        """
        log = self.load_log(target_date)
        log.supplement_entries.append(entry)
        self.save_log(log)
        logger.info(f"Added supplement entry for {target_date}: {entry.supplement_name}")
        return log

    def add_feeling_entry(
        self, target_date: date, entry: BodyFeelingEntry
    ) -> DailyManualLog:
        """Add a body feeling entry to the log.

        Args:
            target_date: Date of the entry
            entry: BodyFeelingEntry to add

        Returns:
            Updated DailyManualLog
        """
        log = self.load_log(target_date)
        log.feeling_entries.append(entry)
        self.save_log(log)
        logger.info(f"Added feeling entry for {target_date}: {entry.feeling_type}")
        return log

    def set_fasting_mode(self, target_date: date, mode: str) -> DailyManualLog:
        """Set the fasting mode for a day.

        Args:
            target_date: Date to set
            mode: Fasting mode (PSMF/OMAD/Water Fast/Normal)

        Returns:
            Updated DailyManualLog
        """
        log = self.load_log(target_date)
        log.fasting_mode = mode
        self.save_log(log)
        logger.info(f"Set fasting mode for {target_date}: {mode}")
        return log

    def get_logs_in_range(
        self, start_date: date, end_date: date
    ) -> List[DailyManualLog]:
        """Get all manual logs in a date range.

        Args:
            start_date: Start date (inclusive)
            end_date: End date (inclusive)

        Returns:
            List of DailyManualLog instances
        """
        logs = []
        current_date = start_date

        while current_date <= end_date:
            log = self.load_log(current_date)
            # Only include logs that have actual data
            if (
                log.diet_entries
                or log.alcohol_entries
                or log.supplement_entries
                or log.feeling_entries
                or log.fasting_mode
            ):
                logs.append(log)

            # Move to next day
            from datetime import timedelta
            current_date += timedelta(days=1)

        return logs
