"""File backend for logging to files."""

from dataclasses import dataclass
from pathlib import Path
from typing import Any

import aiofiles

from ..core.backend import BackendConfig, LoggingBackend, LogRecord
from ..formatters import LogFormatter, PlainFormatter


@dataclass
class FileBackendConfig(BackendConfig):
    """Configuration for file backend."""

    enabled: bool = True
    timeout: float = 5.0
    retry_attempts: int = 3
    retry_delay: float = 0.5
    file_path: str = "app.log"
    max_bytes: int = 10 * 1024 * 1024  # 10MB
    backup_count: int = 5
    encoding: str = "utf-8"
    create_dirs: bool = True


class FileBackend(LoggingBackend):
    """Backend that logs to files with rotation support."""

    def __init__(
        self,
        name: str = "file",
        config: FileBackendConfig | None = None,
        formatter: LogFormatter | None = None,
        **kwargs: Any
    ) -> None:
        """Initialize file backend.
        
        Args:
            name: Backend name
            config: Backend configuration
            formatter: Log formatter to use
            **kwargs: Additional configuration
        """
        self.config = config or FileBackendConfig()

        # Handle file_path from kwargs for backward compatibility
        if 'file_path' in kwargs:
            self.config.file_path = kwargs.pop('file_path')

        # Handle formatter_type from kwargs
        formatter_type = kwargs.pop('formatter_type', None)

        super().__init__(name, self.config, **kwargs)

        # Set up formatter based on type or use provided formatter
        if formatter:
            self.formatter = formatter
        elif formatter_type == "json":
            from ..formatters import JSONFormatter
            self.formatter = JSONFormatter()
        else:
            self.formatter = PlainFormatter()
        self.file_path = Path(self.config.file_path)
        self._file_handle = None
        self._current_size = 0

    async def connect(self) -> bool:
        """Connect to file system and open log file."""
        try:
            # Create directories if they don't exist
            if self.config.create_dirs and self.file_path.parent != Path("."):
                self.file_path.parent.mkdir(parents=True, exist_ok=True)

            # Get current file size if file exists
            if self.file_path.exists():
                self._current_size = self.file_path.stat().st_size
            else:
                self._current_size = 0

            self._connected = True
            return True
        except Exception:
            self._connected = False
            return False

    async def disconnect(self) -> bool:
        """Close file handle."""
        try:
            if self._file_handle:
                await self._file_handle.close()
                self._file_handle = None
            self._connected = False
            return True
        except Exception:
            return False

    async def send_log(self, record: LogRecord) -> bool:
        """Send log record to file.
        
        Args:
            record: The log record to send
            
        Returns:
            True if successfully written, False otherwise
        """
        try:
            formatted_message = self.formatter.format(record)
            message_bytes = formatted_message.encode(self.config.encoding) + b'\n'

            # Check if rotation is needed
            if self._current_size + len(message_bytes) > self.config.max_bytes:
                await self._rotate_file()

            # Write to file
            async with aiofiles.open(
                self.file_path,
                mode='a',
                encoding=self.config.encoding
            ) as f:
                await f.write(formatted_message + '\n')
                await f.flush()

            self._current_size += len(message_bytes)
            return True

        except Exception:
            return False

    async def _rotate_file(self) -> None:
        """Rotate log file when it gets too large."""
        try:
            # Move existing backup files
            for i in range(self.config.backup_count - 1, 0, -1):
                old_file = self.file_path.with_suffix(f".{i}")
                new_file = self.file_path.with_suffix(f".{i + 1}")

                if old_file.exists():
                    if new_file.exists():
                        new_file.unlink()
                    old_file.rename(new_file)

            # Move current file to .1
            if self.file_path.exists():
                backup_file = self.file_path.with_suffix(".1")
                if backup_file.exists():
                    backup_file.unlink()
                self.file_path.rename(backup_file)

            # Reset current size
            self._current_size = 0

        except Exception:
            # If rotation fails, continue with the current file
            pass

    async def health_check(self) -> bool:
        """Check if file system is accessible.
        
        Returns:
            True if file can be written to, False otherwise
        """
        try:
            # Test write access
            test_file = self.file_path.with_suffix(".test")
            async with aiofiles.open(test_file, mode='w') as f:
                await f.write("test")

            # Clean up test file
            if test_file.exists():
                test_file.unlink()

            return True
        except Exception:
            return False
