"""
Test Case Normalization Tool.

Converts test cases from various formats to the QA-MCP standard format.
"""

import re
import uuid
from datetime import datetime

from qa_mcp.core.models import (
    Priority,
    RiskLevel,
    ScenarioType,
    TestCase,
    TestStep,
)


def normalize_testcase(
    input_data: str | dict,
    source_format: str = "auto",
) -> dict:
    """
    Normalize a test case from various formats to QA-MCP standard.

    Args:
        input_data: Test case in string (markdown/gherkin) or dict format
        source_format: Source format - 'auto', 'markdown', 'gherkin', 'json', 'plain'

    Returns:
        Dictionary containing:
        - testcase: Normalized test case in standard format
        - source_format_detected: Detected source format
        - transformations: List of transformations applied
        - warnings: Any warnings during normalization
    """
    transformations = []
    warnings = []

    # Detect format if auto
    if source_format == "auto":
        source_format = _detect_format(input_data)
        transformations.append(f"Format otomatik tespit edildi: {source_format}")

    # Parse based on format
    try:
        if source_format == "gherkin":
            testcase, parse_warnings = _parse_gherkin(input_data)
        elif source_format == "markdown":
            testcase, parse_warnings = _parse_markdown(input_data)
        elif source_format == "json" or isinstance(input_data, dict):
            testcase, parse_warnings = _parse_json(input_data)
        else:  # plain text
            testcase, parse_warnings = _parse_plain_text(input_data)

        warnings.extend(parse_warnings)

    except Exception as e:
        return {
            "testcase": None,
            "source_format_detected": source_format,
            "transformations": transformations,
            "warnings": [f"Parse hatası: {str(e)}"],
            "error": str(e),
        }

    # Validate and fill missing fields
    testcase, fill_warnings = _fill_missing_fields(testcase)
    warnings.extend(fill_warnings)
    transformations.append("Eksik alanlar varsayılan değerlerle dolduruldu")

    # Normalize values
    testcase = _normalize_values(testcase)
    transformations.append("Değerler standartlaştırıldı")

    return {
        "testcase": testcase.model_dump(),
        "source_format_detected": source_format,
        "transformations": transformations,
        "warnings": warnings,
    }


def _detect_format(input_data: str | dict) -> str:
    """Detect the format of input data."""
    if isinstance(input_data, dict):
        return "json"

    text = str(input_data).strip()

    # Gherkin detection
    gherkin_keywords = ["Feature:", "Scenario:", "Given", "When", "Then", "And", "But"]
    if any(kw in text for kw in gherkin_keywords):
        return "gherkin"

    # Markdown detection
    if text.startswith("#") or "## " in text or "**" in text:
        return "markdown"

    return "plain"


def _parse_gherkin(input_data: str) -> tuple[TestCase, list[str]]:
    """Parse Gherkin format test case."""
    warnings = []
    text = str(input_data).strip()
    lines = text.split("\n")

    title = ""
    description = ""
    steps = []
    preconditions = []
    step_number = 0
    current_action = ""

    for line in lines:
        line = line.strip()

        if line.startswith("Feature:"):
            description = line[8:].strip()
        elif line.startswith("Scenario:"):
            title = line[9:].strip()
        elif line.startswith("Given"):
            preconditions.append(line[5:].strip())
        elif line.startswith("When"):
            step_number += 1
            current_action = line[4:].strip()
        elif line.startswith("Then"):
            expected = line[4:].strip()
            if current_action:
                steps.append(
                    TestStep(
                        step_number=step_number,
                        action=current_action,
                        expected_result=expected,
                    )
                )
            current_action = ""
        elif line.startswith("And"):
            # Add to previous context
            if steps:
                steps[-1].expected_result += f"; {line[3:].strip()}"
            elif preconditions:
                preconditions.append(line[3:].strip())

    if not title:
        title = "Gherkin'den içe aktarılan test case senaryosu"
        warnings.append("Scenario adı bulunamadı, varsayılan başlık kullanıldı")

    # Ensure title meets minimum length
    if len(title) < 10:
        title = f"Gherkin Senaryo: {title}"

    if not steps:
        warnings.append("Test adımları çıkarılamadı")
        steps = [
            TestStep(
                step_number=1,
                action="[Gherkin'den çevrilecek - adım tanımlanmalı]",
                expected_result="[Gherkin'den çevrilecek - sonuç tanımlanmalı]",
            )
        ]

    # Build description ensuring minimum length
    if not description:
        description = f"Gherkin senaryosundan dönüştürüldü: {title}"
    if len(description) < 20:
        description = f"Gherkin Feature: {description} - otomatik dönüştürülmüş senaryo"

    # Build expected result ensuring minimum length
    expected = steps[-1].expected_result if steps else "[Beklenen sonuç belirtilmeli]"
    if len(expected) < 10:
        expected = f"Senaryo sonucu: {expected}"

    tc = TestCase(
        id=f"TC-{uuid.uuid4().hex[:8].upper()}",
        title=title,
        description=description,
        preconditions=preconditions if preconditions else ["[Ön koşullar belirtilmeli]"],
        steps=steps,
        expected_result=expected,
        tags=["gherkin-import"],
    )

    return tc, warnings


def _parse_markdown(input_data: str) -> tuple[TestCase, list[str]]:
    """Parse Markdown format test case."""
    warnings = []
    text = str(input_data).strip()
    lines = text.split("\n")

    title = ""
    description = ""
    preconditions = []
    steps = []
    expected_result = ""
    current_section = None
    step_number = 0

    for line in lines:
        line_stripped = line.strip()

        # Title detection
        if line_stripped.startswith("# "):
            title = line_stripped[2:].strip()
        elif line_stripped.startswith("## "):
            section_name = line_stripped[3:].strip().lower()
            if "description" in section_name or "açıklama" in section_name:
                current_section = "description"
            elif "precondition" in section_name or "ön koşul" in section_name:
                current_section = "preconditions"
            elif "step" in section_name or "adım" in section_name:
                current_section = "steps"
            elif "expected" in section_name or "beklenen" in section_name:
                current_section = "expected"
        elif line_stripped.startswith("- ") or line_stripped.startswith("* "):
            content = line_stripped[2:].strip()
            if current_section == "preconditions":
                preconditions.append(content)
            elif current_section == "steps":
                step_number += 1
                # Try to split action and expected
                if " -> " in content:
                    parts = content.split(" -> ")
                    steps.append(
                        TestStep(
                            step_number=step_number,
                            action=parts[0].strip(),
                            expected_result=parts[1].strip()
                            if len(parts) > 1
                            else "[Belirtilmeli]",
                        )
                    )
                else:
                    steps.append(
                        TestStep(
                            step_number=step_number,
                            action=content,
                            expected_result="[Beklenen sonuç belirtilmeli]",
                        )
                    )
        elif line_stripped and current_section == "description":
            description += line_stripped + " "
        elif line_stripped and current_section == "expected":
            expected_result += line_stripped + " "

    if not title:
        title = "Markdown'dan içe aktarılan test case"
        warnings.append("Başlık bulunamadı")

    if not steps:
        warnings.append("Test adımları çıkarılamadı")
        steps = [
            TestStep(
                step_number=1,
                action="[Markdown'dan çevrilecek]",
                expected_result="[Markdown'dan çevrilecek]",
            )
        ]

    tc = TestCase(
        id=f"TC-{uuid.uuid4().hex[:8].upper()}",
        title=title,
        description=description.strip() or f"Markdown'dan dönüştürüldü: {title}",
        preconditions=preconditions if preconditions else ["[Ön koşullar belirtilmeli]"],
        steps=steps,
        expected_result=expected_result.strip() or steps[-1].expected_result,
        tags=["markdown-import"],
    )

    return tc, warnings


def _parse_json(input_data: str | dict) -> tuple[TestCase, list[str]]:
    """Parse JSON/dict format test case."""
    warnings = []

    if isinstance(input_data, str):
        import json

        data = json.loads(input_data)
    else:
        data = input_data

    # Try direct parsing first
    try:
        tc = TestCase(**data)
        return tc, warnings
    except Exception:
        pass

    # Manual field mapping for non-standard formats
    title = (
        data.get("title") or data.get("name") or data.get("summary") or "İçe aktarılan test case"
    )
    description = data.get("description") or data.get("desc") or f"Test case: {title}"

    # Preconditions
    preconditions = data.get("preconditions") or data.get("prerequisites") or []
    if isinstance(preconditions, str):
        preconditions = [preconditions]

    # Steps
    raw_steps = data.get("steps") or data.get("test_steps") or []
    steps = []
    for idx, step in enumerate(raw_steps, 1):
        if isinstance(step, dict):
            steps.append(
                TestStep(
                    step_number=idx,
                    action=step.get("action") or step.get("step") or str(step),
                    expected_result=step.get("expected_result")
                    or step.get("expected")
                    or "[Belirtilmeli]",
                )
            )
        elif isinstance(step, str):
            steps.append(
                TestStep(
                    step_number=idx,
                    action=step,
                    expected_result="[Beklenen sonuç belirtilmeli]",
                )
            )

    if not steps:
        steps = [
            TestStep(
                step_number=1,
                action="[Adım belirtilmeli]",
                expected_result="[Beklenen sonuç belirtilmeli]",
            )
        ]
        warnings.append("Test adımları bulunamadı")

    # Expected result
    expected_result = (
        data.get("expected_result")
        or data.get("expected")
        or data.get("outcome")
        or steps[-1].expected_result
    )

    tc = TestCase(
        id=data.get("id") or f"TC-{uuid.uuid4().hex[:8].upper()}",
        title=title,
        description=description,
        preconditions=preconditions if preconditions else ["[Ön koşullar belirtilmeli]"],
        steps=steps,
        expected_result=expected_result,
        module=data.get("module") or data.get("component"),
        tags=data.get("tags") or data.get("labels") or ["json-import"],
        priority=Priority(data["priority"])
        if data.get("priority") in ["P0", "P1", "P2", "P3"]
        else Priority.P2,
    )

    return tc, warnings


def _parse_plain_text(input_data: str) -> tuple[TestCase, list[str]]:
    """Parse plain text format test case."""
    warnings = []
    text = str(input_data).strip()
    lines = [l.strip() for l in text.split("\n") if l.strip()]

    # First line as title
    title = lines[0] if lines else "Düz metinden içe aktarılan test case"

    # Rest as description/steps
    description = " ".join(lines[1:]) if len(lines) > 1 else title

    # Try to extract numbered steps
    steps = []
    step_pattern = re.compile(r"^(\d+)[.\)]\s*(.+)$")

    for line in lines[1:]:
        match = step_pattern.match(line)
        if match:
            step_num = int(match.group(1))
            action = match.group(2)
            steps.append(
                TestStep(
                    step_number=step_num,
                    action=action,
                    expected_result="[Beklenen sonuç belirtilmeli]",
                )
            )

    if not steps:
        warnings.append(
            "Numaralandırılmış adımlar bulunamadı, tüm metin açıklama olarak kullanıldı"
        )
        steps = [
            TestStep(
                step_number=1,
                action=description[:200] if len(description) > 200 else description,
                expected_result="[Beklenen sonuç belirtilmeli]",
            )
        ]

    tc = TestCase(
        id=f"TC-{uuid.uuid4().hex[:8].upper()}",
        title=title[:200] if len(title) > 200 else title,
        description=description,
        preconditions=["[Ön koşullar belirtilmeli]"],
        steps=steps,
        expected_result="[Beklenen sonuç belirtilmeli]",
        tags=["plain-text-import"],
    )

    warnings.append("Düz metin formatı sınırlı yapı sağlar, manuel düzenleme önerilir")

    return tc, warnings


def _fill_missing_fields(tc: TestCase) -> tuple[TestCase, list[str]]:
    """Fill missing fields with defaults."""
    warnings = []

    if not tc.id:
        tc.id = f"TC-{uuid.uuid4().hex[:8].upper()}"

    if tc.created_at is None:
        tc.created_at = datetime.now()

    if tc.updated_at is None:
        tc.updated_at = tc.created_at

    if tc.risk_level is None:
        tc.risk_level = RiskLevel.MEDIUM
        warnings.append("Risk seviyesi belirtilmedi, 'medium' olarak ayarlandı")

    if tc.priority is None:
        tc.priority = Priority.P2
        warnings.append("Öncelik belirtilmedi, 'P2' olarak ayarlandı")

    if tc.scenario_type is None:
        tc.scenario_type = ScenarioType.POSITIVE

    return tc, warnings


def _normalize_values(tc: TestCase) -> TestCase:
    """Normalize field values."""
    # Trim whitespace
    tc.title = tc.title.strip()
    tc.description = tc.description.strip()
    tc.expected_result = tc.expected_result.strip()

    # Normalize preconditions
    tc.preconditions = [p.strip() for p in tc.preconditions if p.strip()]

    # Normalize steps
    for step in tc.steps:
        step.action = step.action.strip()
        step.expected_result = step.expected_result.strip()

    # Normalize tags (lowercase)
    tc.tags = [t.lower().strip() for t in tc.tags if t.strip()]

    return tc
