from __future__ import annotations

import argparse
import json
import re
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
DEFAULT_INPUT = ROOT / "plugins" / "1c" / "training" / "examples" / "instruction.examples.jsonl"

SECRET_PATTERNS = {
    "password assignment": re.compile(r"(?i)(password|passwd|пароль)\s*[:=]\s*\S+"),
    "token assignment": re.compile(r"(?i)(token|api[_-]?key|secret|ключ)\s*[:=]\s*\S+"),
    "connection string": re.compile(r"(?i)(server|host|database|uid|user id|pwd)\s*="),
    "private key": re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----"),
}

VALID_ROLES = {"system", "user", "assistant", "tool"}


def scan_secrets(text: str) -> list[str]:
    return [name for name, pattern in SECRET_PATTERNS.items() if pattern.search(text)]


def iter_jsonl(path: Path) -> list[tuple[int, dict]]:
    records: list[tuple[int, dict]] = []
    with path.open("r", encoding="utf-8") as handle:
        for line_number, line in enumerate(handle, start=1):
            line = line.strip()
            if not line:
                continue
            try:
                data = json.loads(line)
            except json.JSONDecodeError as exc:
                raise ValueError(f"{path}:{line_number}: invalid JSON: {exc}") from exc
            if not isinstance(data, dict):
                raise ValueError(f"{path}:{line_number}: record must be an object")
            records.append((line_number, data))
    return records


def validate_record(path: Path, line_number: int, record: dict) -> list[str]:
    errors: list[str] = []
    prefix = f"{path}:{line_number}"

    if not record.get("id"):
        errors.append(f"{prefix}: id is required")

    messages = record.get("messages")
    if not isinstance(messages, list) or len(messages) < 2:
        errors.append(f"{prefix}: messages must contain at least 2 items")
        return errors

    has_user = False
    has_assistant = False
    for index, message in enumerate(messages):
        msg_prefix = f"{prefix}: messages[{index}]"
        if not isinstance(message, dict):
            errors.append(f"{msg_prefix}: message must be an object")
            continue

        role = message.get("role")
        content = message.get("content")
        if role not in VALID_ROLES:
            errors.append(f"{msg_prefix}: invalid role `{role}`")
        if not isinstance(content, str) or not content.strip():
            errors.append(f"{msg_prefix}: content is required")
            continue

        if role == "user":
            has_user = True
        if role == "assistant":
            has_assistant = True

        matches = scan_secrets(content)
        for match in matches:
            errors.append(f"{msg_prefix}: possible secret detected: {match}")

    if not has_user:
        errors.append(f"{prefix}: at least one user message is required")
    if not has_assistant:
        errors.append(f"{prefix}: at least one assistant message is required")

    return errors


def main() -> int:
    parser = argparse.ArgumentParser(description="Validate 1C training JSONL data.")
    parser.add_argument("path", nargs="?", type=Path, default=DEFAULT_INPUT)
    args = parser.parse_args()

    errors: list[str] = []
    try:
        records = iter_jsonl(args.path)
    except Exception as exc:
        print(f"Failed to read training data: {exc}", file=sys.stderr)
        return 1

    for line_number, record in records:
        errors.extend(validate_record(args.path, line_number, record))

    if errors:
        print("1C training data validation failed:", file=sys.stderr)
        for error in errors:
            print(f"- {error}", file=sys.stderr)
        return 1

    print(f"Validated {len(records)} 1C training record(s): {args.path}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
