import time
from typing import Any, Optional
from .utils import get_thread_info, format_value


class OutputFormatter:
    def __init__(
        self,
        prefix: str = "",
        include_thread_info: bool = False,
        include_timestamp: bool = True,
        use_colors: bool = True,
    ):
        self.prefix = prefix
        self.include_thread_info = include_thread_info
        self.include_timestamp = include_timestamp
        self.use_colors = use_colors

        self.colors = {
            'reset': '\033[0m' if self.use_colors else '',
            'bold': '\033[1m' if self.use_colors else '',
            'dim': '\033[2m' if self.use_colors else '',
            'blue': '\033[34m' if self.use_colors else '',
            'green': '\033[32m' if self.use_colors else '',
            'yellow': '\033[33m' if self.use_colors else '',
            'red': '\033[31m' if self.use_colors else '',
            'cyan': '\033[36m' if self.use_colors else '',
        }

    def _get_indent(self, indent_level: int) -> str:
        if not self.prefix:
            return ""
        return "  " * indent_level

    def format_timestamp(self) -> str:
        if self.include_timestamp:
            return time.strftime('%H:%M:%S', time.localtime(time.time()))
        return ""

    def format_line(
        self,
        event: str,
        filename: str, # noqa
        lineno: int,
        func_name: str,
        source_line: str = "",
        indent: int = 0,
    ) -> str:
        parts = [
            self.prefix,
            self._get_indent(indent)
        ]

        if self.include_thread_info:
            parts.append(get_thread_info())

        if self.include_timestamp:
            timestamp = self.format_timestamp()
            parts.append(f"{timestamp:8} ")

        if self.use_colors:
            event_color = {
                'call': self.colors['blue'],
                'line': self.colors['reset'],
                'return': self.colors['green'],
                'exception': self.colors['red'],
            }.get(
                event,
                self.colors['reset']
            )
            parts.append(f"{event_color}{event:>8}{self.colors['reset']} ")
        else:
            parts.append(f"{event:>8} ")

        parts.append(f"{lineno:>4} ")
        parts.append(f"{func_name}()")

        if source_line:
            if self.use_colors:
                parts.append(f" {self.colors['dim']}{source_line}{self.colors['reset']}")
            else:
                parts.append(f" {source_line}")

        return "".join(parts)

    def format_var(
        self,
        var_type: str,
        name: str,
        value: Any,
        indent: int = 0,
    ) -> str:
        parts = [
            self.prefix,
            self._get_indent(indent)
        ]

        if self.use_colors:
            type_color = {
                'new': self.colors['green'],
                'modified': self.colors['yellow'],
                'deleted': self.colors['red'],
                'watch': self.colors['cyan'],
                'var': self.colors['cyan']
            }.get(
                var_type,
                self.colors['reset']
            )
            parts.append(f"{type_color}{var_type:>12}{self.colors['reset']}: ")
        else:
            parts.append(f"{var_type:>12}: ")

        parts.append(f"{name} = {format_value(value)}")

        return "".join(parts)

    def format_elapsed(self, elapsed: float, indent: int = 0) -> str:
        parts = [
            self.prefix,
            self._get_indent(indent)
        ]

        if self.use_colors:
            parts.append(f"{self.colors['dim']}Elapsed time: {elapsed*1000:.3f}ms{self.colors['reset']}\n")
        else:
            parts.append(f"Elapsed time: {elapsed*1000:.3f}ms\n")

        return "".join(parts)

    def format_exception(self, exc_type: str, exc_value: str, indent: int = 0) -> str:
        parts = [
            self.prefix,
            self._get_indent(indent)
        ]

        if self.use_colors:
            parts.append(f"{self.colors['red']}Exception: {exc_type}: {exc_value}{self.colors['reset']}\n")
        else:
            parts.append(f"Exception: {exc_type}: {exc_value}\n")

        return "".join(parts)


class OutputHandler:
    def __init__(self, writer, formatter: Optional[OutputFormatter] = None):
        self.writer = writer
        self.formatter = formatter or OutputFormatter()
        self.indent_level = 0

    def increase_indent(self):
        self.indent_level += 1

    def decrease_indent(self):
        self.indent_level = max(0, self.indent_level - 1)

    def write_line(self, **kwargs):
        line = self.formatter.format_line(indent=self.indent_level, **kwargs)
        self.writer.write(line + "\n")

    def write_var(self, **kwargs):
        line = self.formatter.format_var(indent=self.indent_level, **kwargs)
        self.writer.write(line + "\n")

    def write_elapsed(self, elapsed: float):
        line = self.formatter.format_elapsed(indent=self.indent_level, elapsed=elapsed)
        self.writer.write(line)

    def write_exception(self, exc_type: str, exc_value: str):
        line = self.formatter.format_exception(
            indent=self.indent_level,
            exc_type=exc_type,
            exc_value=exc_value
        )
        self.writer.write(line)

    def write_raw(self, text: str):
        self.writer.write(text)
