from __future__ import annotations

import re
from dataclasses import dataclass

from ..schema import FileFacts, ImportRef, Span, SymbolDef
from ..utils import normalize_whitespace


_JS_IMPORT_RE = re.compile(
    r"""^\s*import\s+(?:type\s+)?(?:[\w*\s{},]+\s+from\s+)?["'](?P<mod>[^"']+)["']\s*;?\s*$"""
)
_JS_REQUIRE_RE = re.compile(
    r"""^\s*(?:const|let|var)\s+\w+\s*=\s*require\(\s*["'](?P<mod>[^"']+)["']\s*\)\s*;?\s*$"""
)
_JS_EXPORT_FROM_RE = re.compile(
    r"""^\s*export\s+(?:\*\s+from|{[^}]+}\s+from)\s+["'](?P<mod>[^"']+)["']\s*;?\s*$"""
)

_JS_CLASS_RE = re.compile(r"^\s*(?:export\s+)?class\s+(?P<name>[A-Za-z_$][\w$]*)\b")
_JS_FUNC_RE = re.compile(
    r"^\s*(?:export\s+)?function\s+(?P<name>[A-Za-z_$][\w$]*)\s*\("
)
_JS_ARROW_RE = re.compile(
    r"^\s*(?:export\s+)?(?:const|let|var)\s+(?P<name>[A-Za-z_$][\w$]*)\s*=\s*(?:async\s+)?\([^)]*\)\s*=>"
)


def _span_for_line(line_no: int, line: str) -> Span:
    return {
        "start_line": line_no,
        "end_line": line_no,
        "start_col": 0,
        "end_col": max(0, len(line)),
    }


def _symbol_id(path: str, qualname: str, kind: str, span: Span) -> str:
    return f"{path}::{kind}::{qualname}::{span['start_line']}:{span['end_line']}"


@dataclass
class RegexSkeletonParser:
    """
    Code-first skeleton extraction for JS/TS when we don't want heavy dependencies.
    This is intentionally lightweight and conservative.
    """

    def parse_js_ts(self, code: str, path: str, language: str) -> FileFacts:
        lines = code.splitlines()
        imports: list[ImportRef] = []
        symbols: list[SymbolDef] = []

        for i, line in enumerate(lines, start=1):
            m = _JS_IMPORT_RE.match(line) or _JS_REQUIRE_RE.match(line) or _JS_EXPORT_FROM_RE.match(line)
            if m:
                imports.append(
                    {
                        "module": m.group("mod"),
                        "alias": "",
                        "level": 0,
                        "span": _span_for_line(i, line),
                    }
                )
                continue

            m = _JS_CLASS_RE.match(line)
            if m:
                name = m.group("name")
                sp = _span_for_line(i, line)
                qn = name
                symbols.append(
                    {
                        "symbol_id": _symbol_id(path, qn, "class", sp),
                        "kind": "class",
                        "name": name,
                        "qualname": qn,
                        "path": path,
                        "span": sp,
                        "signature": normalize_whitespace(line.strip()),
                        "decorators": [],
                        "doc_firstline": "",
                        "returns": "",
                    }
                )
                continue

            m = _JS_FUNC_RE.match(line)
            if m:
                name = m.group("name")
                sp = _span_for_line(i, line)
                qn = name
                symbols.append(
                    {
                        "symbol_id": _symbol_id(path, qn, "function", sp),
                        "kind": "function",
                        "name": name,
                        "qualname": qn,
                        "path": path,
                        "span": sp,
                        "signature": normalize_whitespace(line.strip()),
                        "decorators": [],
                        "doc_firstline": "",
                        "returns": "",
                    }
                )
                continue

            m = _JS_ARROW_RE.match(line)
            if m:
                name = m.group("name")
                sp = _span_for_line(i, line)
                qn = name
                symbols.append(
                    {
                        "symbol_id": _symbol_id(path, qn, "function", sp),
                        "kind": "function",
                        "name": name,
                        "qualname": qn,
                        "path": path,
                        "span": sp,
                        "signature": normalize_whitespace(line.strip()),
                        "decorators": [],
                        "doc_firstline": "",
                        "returns": "",
                    }
                )
                continue

        return {
            "path": path,
            "language": language,  # type: ignore[typeddict-item]
            "imports": imports,
            "symbols": symbols,
            "calls": [],
            "parse_errors": [],
        }

