import sys
import json
import os
from datetime import datetime
from .colors import ConsoleColors


class BaseHandler:
    def __init__(self, level="DEBUG"):
        self.level = level
        self.levels = ["DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL"]
    
    def should_log(self, level):
        if level.upper() not in self.levels:
            return True
        return self.levels.index(level.upper()) >= self.levels.index(self.level.upper())
    
    def emit(self, record):
        raise NotImplementedError


class ConsoleHandler(BaseHandler):
    def __init__(self, level="DEBUG", stream=None, colors=True):
        super().__init__(level)
        self.stream = stream or sys.stdout
        self.colors = colors
    
    def emit(self, record):
        if not self.should_log(record.get("level", "INFO")):
            return
        message = record.get("formatted_message", record.get("message", ""))
        if not self.colors:
            import re
            message = re.sub(r'\033\[[0-9;]*m', '', message)
        self.stream.write(message + "\n")
        self.stream.flush()


class FileHandler(BaseHandler):
    def __init__(self, filename, level="DEBUG", mode="a", encoding="utf-8"):
        super().__init__(level)
        self.filename = filename
        self.mode = mode
        self.encoding = encoding
        self._ensure_dir()
    
    def _ensure_dir(self):
        dirname = os.path.dirname(self.filename)
        if dirname and not os.path.exists(dirname):
            os.makedirs(dirname, exist_ok=True)
    
    def emit(self, record):
        if not self.should_log(record.get("level", "INFO")):
            return
        message = record.get("message", "")
        timestamp = record.get("timestamp", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        level = record.get("level", "INFO")
        line = f"[{timestamp}] [{level}] {message}\n"
        with open(self.filename, self.mode, encoding=self.encoding) as f:
            f.write(line)


class RotatingFileHandler(FileHandler):
    def __init__(self, filename, level="DEBUG", max_bytes=10485760, backup_count=5, encoding="utf-8"):
        super().__init__(filename, level, "a", encoding)
        self.max_bytes = max_bytes
        self.backup_count = backup_count
    
    def _should_rotate(self):
        if not os.path.exists(self.filename):
            return False
        return os.path.getsize(self.filename) >= self.max_bytes
    
    def _rotate(self):
        if not os.path.exists(self.filename):
            return
        for i in range(self.backup_count - 1, 0, -1):
            src = f"{self.filename}.{i}"
            dst = f"{self.filename}.{i + 1}"
            if os.path.exists(src):
                if os.path.exists(dst):
                    os.remove(dst)
                os.rename(src, dst)
        dst = f"{self.filename}.1"
        if os.path.exists(dst):
            os.remove(dst)
        os.rename(self.filename, dst)
    
    def emit(self, record):
        if self._should_rotate():
            self._rotate()
        super().emit(record)


class JSONHandler(BaseHandler):
    def __init__(self, filename, level="DEBUG", encoding="utf-8"):
        super().__init__(level)
        self.filename = filename
        self.encoding = encoding
        self._ensure_dir()
    
    def _ensure_dir(self):
        dirname = os.path.dirname(self.filename)
        if dirname and not os.path.exists(dirname):
            os.makedirs(dirname, exist_ok=True)
    
    def emit(self, record):
        if not self.should_log(record.get("level", "INFO")):
            return
        log_entry = {
            "timestamp": record.get("timestamp", datetime.now().isoformat()),
            "level": record.get("level", "INFO"),
            "message": record.get("message", ""),
        }
        if "error" in record and record["error"]:
            log_entry["error"] = {
                "type": type(record["error"]).__name__,
                "message": str(record["error"]),
            }
        if "context" in record:
            log_entry["context"] = record["context"]
        with open(self.filename, "a", encoding=self.encoding) as f:
            f.write(json.dumps(log_entry) + "\n")


class MemoryHandler(BaseHandler):
    def __init__(self, level="DEBUG", capacity=1000):
        super().__init__(level)
        self.capacity = capacity
        self.buffer = []
    
    def emit(self, record):
        if not self.should_log(record.get("level", "INFO")):
            return
        self.buffer.append(record)
        if len(self.buffer) > self.capacity:
            self.buffer.pop(0)
    
    def get_logs(self):
        return list(self.buffer)
    
    def clear(self):
        self.buffer.clear()
