"""API endpoints for tree markdown import/export."""
from typing import Annotated
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy.orm import selectinload

from app.core.database import get_db
from app.models.tree import Tree
from app.models.user import User
from app.api.deps import get_current_active_user, require_engineer_or_admin
from app.core.permissions import can_access_tree, can_edit_tree
from app.schemas.tree_markdown import (
    TreeMarkdownExportResponse,
    TreeMarkdownImportRequest,
    TreeMarkdownValidationResponse,
    MarkdownValidationError,
)
from app.services.tree_markdown_service import serialize_tree_to_markdown
from app.services.tree_markdown_parser import parse_markdown_to_tree
from app.services.tree_markdown_validator import validate_tree_markdown

router = APIRouter(prefix="/trees", tags=["tree-markdown"])


@router.get("/{tree_id}/export-markdown", response_model=TreeMarkdownExportResponse)
async def export_tree_markdown(
    tree_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_active_user)],
):
    """Export a tree's JSONB structure as ResolutionFlow markdown."""
    result = await db.execute(
        select(Tree).where(Tree.id == tree_id, Tree.deleted_at.is_(None))
    )
    tree = result.scalar_one_or_none()
    if not tree:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Tree not found")

    if not can_access_tree(current_user, tree):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied")

    metadata = {
        "name": tree.name or "",
        "description": tree.description or "",
        "category": tree.category or "",
    }
    markdown = serialize_tree_to_markdown(tree.tree_structure, metadata=metadata)
    return TreeMarkdownExportResponse(markdown=markdown)


@router.put("/{tree_id}/import-markdown", response_model=TreeMarkdownValidationResponse)
async def import_tree_markdown(
    tree_id: UUID,
    body: TreeMarkdownImportRequest,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_engineer_or_admin)],
):
    """Parse markdown and update a tree's JSONB structure."""
    result = await db.execute(
        select(Tree).where(Tree.id == tree_id, Tree.deleted_at.is_(None))
    )
    tree = result.scalar_one_or_none()
    if not tree:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Tree not found")

    if not can_edit_tree(current_user, tree):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied")

    parse_result = parse_markdown_to_tree(body.markdown)

    has_errors = any(e.severity == "error" for e in parse_result.errors)
    if has_errors:
        return TreeMarkdownValidationResponse(
            valid=False,
            errors=[
                MarkdownValidationError(
                    line=e.line, column=e.column, message=e.message, severity=e.severity
                )
                for e in parse_result.errors
            ],
            tree_structure=None,
        )

    # Apply the parsed tree structure
    tree.tree_structure = parse_result.tree_structure
    await db.commit()

    return TreeMarkdownValidationResponse(
        valid=True,
        errors=[
            MarkdownValidationError(
                line=e.line, column=e.column, message=e.message, severity=e.severity
            )
            for e in parse_result.errors
        ],
        tree_structure=parse_result.tree_structure,
    )


@router.post("/validate-markdown", response_model=TreeMarkdownValidationResponse)
async def validate_markdown(
    body: TreeMarkdownImportRequest,
    current_user: Annotated[User, Depends(get_current_active_user)],
):
    """Validate markdown without saving. Returns errors and preview JSONB."""
    parse_result = parse_markdown_to_tree(body.markdown)
    all_errors = validate_tree_markdown(body.markdown)

    # Deduplicate errors by message
    seen: set[str] = set()
    unique_errors: list[MarkdownValidationError] = []
    for e in all_errors:
        key = f"{e.line}:{e.column}:{e.message}"
        if key not in seen:
            seen.add(key)
            unique_errors.append(
                MarkdownValidationError(
                    line=e.line, column=e.column, message=e.message, severity=e.severity
                )
            )

    has_hard_errors = any(e.severity == "error" for e in unique_errors)

    return TreeMarkdownValidationResponse(
        valid=not has_hard_errors,
        errors=unique_errors,
        tree_structure=parse_result.tree_structure,
        metadata=parse_result.metadata,
    )
