"""
API routes for Jira vein.
"""

import base64
import logging
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import PlainTextResponse, StreamingResponse
from typing import Optional, Union
from io import BytesIO

from ..core.auth import get_jira_credentials, JiraCredentials
from ..core.client import connect_jira, JiraClientError
from ..core.config import settings
from ..core.query import JQL, Queries
from ..models.ticket import Ticket, TicketDetail, TicketList
from ..models.formatter import format_ticket_list, format_ticket_detail

logger = logging.getLogger(__name__)
router = APIRouter()


def _download_attachments(jira, ticket: TicketDetail) -> TicketDetail:
    """Download attachment content and populate base64 field."""
    for att in ticket.attachments:
        try:
            response = jira._session.get(att.url)
            if response.status_code == 200:
                att.content_base64 = base64.b64encode(response.content).decode("utf-8")
        except Exception:
            pass  # Skip failed downloads
    return ticket


def _search(creds: JiraCredentials, jql: JQL, page: int, page_size: int) -> TicketList:
    jira = connect_jira(creds.email, creds.token)
    start = (page - 1) * page_size
    issues = jira.search_issues(jql.build(), startAt=start, maxResults=page_size)
    tickets = [Ticket.from_jira(i, settings.jira_url) for i in issues]
    return TicketList(tickets=tickets, total=issues.total, page=page, page_size=page_size)


def _maybe_text(data: Union[TicketList, TicketDetail], text: bool):
    if not text:
        return data
    if isinstance(data, TicketList):
        return PlainTextResponse(format_ticket_list(data))
    return PlainTextResponse(format_ticket_detail(data))


@router.get("/health")
def health(creds: JiraCredentials = Depends(get_jira_credentials)):
    try:
        jira = connect_jira(creds.email, creds.token)
        me = jira.myself()
        return {"status": "ok", "user": me["displayName"]}
    except Exception as e:
        raise HTTPException(500, str(e))


@router.get("/mine")
def my_tickets(
    creds: JiraCredentials = Depends(get_jira_credentials),
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    project: Optional[str] = None,
    text: bool = False,
):
    """Get my assigned open tickets."""
    try:
        return _maybe_text(_search(creds, Queries.my_tickets(project), page, page_size), text)
    except Exception as e:
        raise HTTPException(500, str(e))


@router.get("/backlog")
def backlog(
    creds: JiraCredentials = Depends(get_jira_credentials),
    project: str = Query(...),
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    text: bool = False,
):
    """Get backlog tickets for a project."""
    try:
        return _maybe_text(_search(creds, Queries.backlog(project), page, page_size), text)
    except Exception as e:
        raise HTTPException(500, str(e))


@router.get("/sprint")
def current_sprint(
    creds: JiraCredentials = Depends(get_jira_credentials),
    project: str = Query(...),
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    text: bool = False,
):
    """Get current sprint tickets for a project."""
    try:
        return _maybe_text(_search(creds, Queries.current_sprint(project), page, page_size), text)
    except Exception as e:
        raise HTTPException(500, str(e))


@router.get("/ticket/{key}")
def get_ticket(
    key: str,
    creds: JiraCredentials = Depends(get_jira_credentials),
    text: bool = False,
    include_attachments: bool = False,
    include_children: bool = True,
):
    """Get ticket details with comments, attachments, and child work items."""
    try:
        jira = connect_jira(creds.email, creds.token)
        issue = jira.issue(key, expand="comments")
        ticket = TicketDetail.from_jira(issue, settings.jira_url)
        if include_attachments and ticket.attachments:
            ticket = _download_attachments(jira, ticket)

        # Fetch child work items if requested and ticket has subtasks
        children = []
        if include_children and ticket.subtasks:
            # Fetch all children in one query
            child_jql = f"key in ({','.join(ticket.subtasks)})"
            child_issues = jira.search_issues(child_jql, maxResults=len(ticket.subtasks))
            children = [Ticket.from_jira(i, settings.jira_url) for i in child_issues]
            # Sort children by key
            children.sort(key=lambda t: t.key)

        # Return as special format that includes children
        if text:
            from ..models.formatter import format_ticket_with_children
            return PlainTextResponse(format_ticket_with_children(ticket, children))

        # For JSON, add children to response
        result = ticket.model_dump()
        result["children"] = [c.model_dump() for c in children]
        return result

    except Exception as e:
        # Return the actual Jira error for debugging
        raise HTTPException(404, f"Error fetching {key}: {str(e)}")


@router.post("/search")
def search(
    jql: str,
    creds: JiraCredentials = Depends(get_jira_credentials),
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    text: bool = False,
):
    """Search with raw JQL."""
    try:
        return _maybe_text(_search(creds, JQL().raw(jql), page, page_size), text)
    except Exception as e:
        raise HTTPException(500, str(e))


@router.post("/epic/{key}/process")
def process_epic(
    key: str,
    creds: JiraCredentials = Depends(get_jira_credentials),
):
    """Process epic: fetch epic and all children, save to files."""
    import time
    import json
    from pathlib import Path
    from fastapi.responses import StreamingResponse

    logger.info(f"EPIC endpoint called: key={key}, email={creds.email}")

    def generate():
        try:
            logger.info(f"Starting EPIC process for {key}")
            jira = connect_jira(creds.email, creds.token)
            logger.info(f"Connected to Jira for {key}")

            # Fetch epic
            yield json.dumps({"status": "fetching_epic", "completed": 0, "total": 0}) + "\n"
            logger.info(f"Sent fetching_epic status for {key}")
            time.sleep(0.5)

            logger.info(f"Fetching issue {key}")
            epic_issue = jira.issue(key, expand="comments")
            logger.info(f"Got issue {key}")
            epic = TicketDetail.from_jira(epic_issue, settings.jira_url)
            logger.info(f"Parsed epic: {epic.key} with {len(epic.subtasks)} subtasks")

            # Get children keys from subtasks
            if not epic.subtasks:
                yield json.dumps({"status": "no_children", "completed": 0, "total": 0}) + "\n"
                return

            total = len(epic.subtasks)

            # Create storage folder in larder
            larder_path = Path(__file__).parent.parent.parent.parent / "larder" / "jira_epics" / key
            larder_path.mkdir(parents=True, exist_ok=True)

            # Save epic
            epic_file = larder_path / f"{key}.json"
            with open(epic_file, "w") as f:
                json.dump(epic.model_dump(), f, indent=2, default=str)

            yield json.dumps({"status": "processing", "completed": 0, "total": total}) + "\n"

            # Fetch each child
            children = []
            for idx, child_key in enumerate(epic.subtasks, 1):
                time.sleep(0.8)  # Human speed

                try:
                    child_issue = jira.issue(child_key, expand="comments")
                    child = TicketDetail.from_jira(child_issue, settings.jira_url)

                    # Save child
                    child_file = larder_path / f"{child_key}.json"
                    with open(child_file, "w") as f:
                        json.dump(child.model_dump(), f, indent=2, default=str)

                    # Collect children for text formatting
                    children.append(Ticket.from_jira(child_issue, settings.jira_url))

                    yield json.dumps({"status": "processing", "completed": idx, "total": total}) + "\n"
                except Exception as e:
                    import traceback
                    yield json.dumps({
                        "status": "error",
                        "completed": idx,
                        "total": total,
                        "error": str(e),
                        "error_type": type(e).__name__,
                        "child_key": child_key,
                        "traceback": traceback.format_exc()
                    }) + "\n"

            # Format as text for display
            from ..models.formatter import format_ticket_with_children
            formatted_text = format_ticket_with_children(epic, children)

            yield json.dumps({
                "status": "complete",
                "completed": total,
                "total": total,
                "path": str(larder_path),
                "text": formatted_text
            }) + "\n"

        except Exception as e:
            import traceback
            yield json.dumps({
                "status": "error",
                "error": str(e),
                "error_type": type(e).__name__,
                "traceback": traceback.format_exc()
            }) + "\n"

    return StreamingResponse(generate(), media_type="application/x-ndjson")


@router.get("/epic/{key}/status")
def get_epic_status(key: str):
    """Check if epic has been processed and files exist."""
    from pathlib import Path
    import json

    larder_path = Path(__file__).parent.parent.parent.parent / "larder" / "jira_epics" / key

    if not larder_path.exists():
        return {"processed": False}

    files = list(larder_path.glob("*.json"))
    return {
        "processed": True,
        "path": str(larder_path),
        "files": [f.name for f in files],
        "count": len(files)
    }


@router.get("/attachment/{attachment_id}")
def get_attachment(
    attachment_id: str,
    creds: JiraCredentials = Depends(get_jira_credentials),
):
    """Stream attachment content directly from Jira."""
    jira = connect_jira(creds.email, creds.token)
    att_url = f"{settings.jira_url}/rest/api/2/attachment/content/{attachment_id}"
    response = jira._session.get(att_url, allow_redirects=True)
    if response.status_code != 200:
        raise HTTPException(404, f"Attachment not found: {attachment_id}")
    content_type = response.headers.get("Content-Type", "application/octet-stream")
    return StreamingResponse(
        BytesIO(response.content),
        media_type=content_type,
    )
