"""Tests para parser_registry."""

from __future__ import annotations

import asyncio
import sys
import os
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, AsyncMock

# Añadir python/types/core al path para importar BaseParser y ParseResult
_registry_root = Path(__file__).resolve().parents[4]
sys.path.insert(0, str(_registry_root / "python" / "types" / "core"))
sys.path.insert(0, str(_registry_root / "python" / "functions" / "core"))

from parser_registry import ParserRegistry, get_registry


# ------------------------------------------------------------------
# Helpers: parser stub que implementa BaseParser
# ------------------------------------------------------------------

class StubParser:
    """Parser de prueba para tests. No hereda ABC para evitar deps."""

    def __init__(self, extensions: list[str], name: str = "stub") -> None:
        self._extensions = extensions
        self._name = name

    @property
    def supported_extensions(self) -> list[str]:
        return self._extensions

    def can_parse(self, path: str) -> bool:
        return Path(path).suffix.lower() in self._extensions

    async def parse(self, source, **kwargs):
        return MagicMock(parser_name=self._name, source_path=str(source))

    async def parse_content(self, content: str, source_path=None, **kwargs):
        return MagicMock(parser_name=self._name, source_path=source_path)


def _run(coro):
    """Helper sincrono para ejecutar corrutinas en tests."""
    return asyncio.get_event_loop().run_until_complete(coro)


# ------------------------------------------------------------------
# Tests
# ------------------------------------------------------------------

def test_registrar_parser_custom():
    """registrar parser custom"""
    registry = ParserRegistry()
    stub = StubParser([".foo"])
    registry.register("foo", stub)

    assert "foo" in registry.list_parsers()
    assert ".foo" in registry.list_supported_extensions()
    assert registry.get_parser("foo") is stub


def test_resolver_por_extension():
    """resolver parser por extension de archivo"""
    registry = ParserRegistry()
    md_parser = StubParser([".md", ".markdown"], "markdown")
    registry.register("markdown", md_parser)

    result = registry.get_parser_for_file("documento.md")
    assert result is md_parser

    result2 = registry.get_parser_for_file("readme.markdown")
    assert result2 is md_parser


def test_parse_file():
    """parsear archivo existente con extension registrada"""
    registry = ParserRegistry()
    txt_parser = StubParser([".txt"], "text")
    registry.register("text", txt_parser)

    # Crear archivo temporal .txt
    with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as f:
        f.write(b"hola mundo")
        tmp_path = f.name

    try:
        result = _run(registry.parse(tmp_path))
        assert result.parser_name == "text"
    finally:
        os.unlink(tmp_path)


def test_parse_string():
    """parsear string de contenido sin path"""
    registry = ParserRegistry()
    text_parser = StubParser([".txt"], "text")
    registry.register("text", text_parser)

    # Contenido con newlines → se trata como contenido directo
    content = "linea 1\nlinea 2\nlinea 3"
    result = _run(registry.parse(content))
    assert result.parser_name == "text"


def test_unregister():
    """desregistrar parser elimina nombre y extensiones"""
    registry = ParserRegistry()
    stub = StubParser([".bar"])
    registry.register("bar", stub)
    assert "bar" in registry.list_parsers()

    registry.unregister("bar")
    assert "bar" not in registry.list_parsers()
    assert ".bar" not in registry.list_supported_extensions()
    assert registry.get_parser("bar") is None


def test_extension_desconocida_fallback_text():
    """extension desconocida hace fallback al parser text"""
    registry = ParserRegistry()
    text_parser = StubParser([".txt"], "text")
    registry.register("text", text_parser)

    # Crear archivo con extension no registrada
    with tempfile.NamedTemporaryFile(suffix=".xyz", delete=False) as f:
        f.write(b"contenido")
        tmp_path = f.name

    try:
        result = _run(registry.parse(tmp_path))
        assert result.parser_name == "text"
    finally:
        os.unlink(tmp_path)


if __name__ == "__main__":
    tests = [
        test_registrar_parser_custom,
        test_resolver_por_extension,
        test_parse_file,
        test_parse_string,
        test_unregister,
        test_extension_desconocida_fallback_text,
    ]

    passed = 0
    failed = 0
    for t in tests:
        try:
            t()
            print(f"PASS: {t.__doc__}")
            passed += 1
        except Exception as e:
            print(f"FAIL: {t.__doc__} — {e}")
            failed += 1

    print(f"---\nResults: {passed} passed, {failed} failed")
    if failed:
        sys.exit(1)
