"""REST API endpoints for external provider integrations.

Provides endpoints for managing GitHub, GitLab, and Jira integrations
from the dashboard UI.
"""
from __future__ import annotations

from typing import Any, Dict, List

from fastapi import APIRouter, HTTPException, status
from pydantic import BaseModel, Field

from proxym.external.config import get_config_manager, ProviderConfig
from proxym.external.providers import get_provider

router = APIRouter(prefix="/external", tags=["external"])


# ── Pydantic Models ──────────────────────────────────────────

class ProviderConfigRequest(BaseModel):
    """Request to configure a provider."""
    api_key: str = Field(..., description="API token or personal access token")
    base_url: str | None = Field(None, description="Base URL for self-hosted instances")
    email: str | None = Field(None, description="Email (required for Jira)")
    name: str = Field("default", description="Configuration name")


class ProviderConfigResponse(BaseModel):
    """Response with provider configuration."""
    provider: str
    name: str
    base_url: str | None
    email: str | None
    enabled: bool
    has_key: bool
    test_success: bool = False
    test_message: str = ""


class TestResult(BaseModel):
    """Provider test result."""
    success: bool
    message: str


class ExternalProjectResponse(BaseModel):
    """External project representation."""
    id: str
    external_id: str | None
    name: str
    namespace: str | None
    description: str | None
    url: str
    provider: str


class ExternalIssueResponse(BaseModel):
    """External issue representation."""
    id: str
    number: int
    title: str
    description: str | None
    state: str
    url: str
    labels: List[str]


class CreateProjectRequest(BaseModel):
    """Request to create a project."""
    name: str
    description: str | None = None
    namespace: str | None = None


class CreateIssueRequest(BaseModel):
    """Request to create an issue."""
    title: str
    description: str | None = None
    labels: List[str] = []


class SyncTicketRequest(BaseModel):
    """Request to sync a ticket to external issue."""
    project_id: str | None = None
    labels: List[str] = ["proxym-sync"]


# ── Configuration Endpoints ──────────────────────────────────

@router.get("/providers", response_model=List[ProviderConfigResponse])
async def list_providers() -> List[ProviderConfigResponse]:
    """List all configured external providers."""
    manager = get_config_manager()
    configs = manager.list_providers()

    return [
        ProviderConfigResponse(
            provider=c.provider,
            name=c.name or "default",
            base_url=c.base_url,
            email=c.email,
            enabled=c.enabled,
            has_key=bool(c.api_key),
        )
        for c in configs
    ]


@router.post("/providers/{provider}", response_model=ProviderConfigResponse)
async def configure_provider(
    provider: str,
    request: ProviderConfigRequest,
) -> ProviderConfigResponse:
    """Configure an external provider."""
    if provider not in ["github", "gitlab", "jira"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Unsupported provider: {provider}"
        )

    if provider == "jira" and not request.email:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Jira requires email for authentication"
        )

    config = ProviderConfig(
        provider=provider,
        api_key=request.api_key,
        base_url=request.base_url,
        email=request.email,
        name=request.name,
    )

    manager = get_config_manager()
    manager.add_provider(config)

    # Test the configuration
    success, message = await manager.test_provider(provider, request.name)

    return ProviderConfigResponse(
        provider=provider,
        name=request.name,
        base_url=request.base_url,
        email=request.email,
        enabled=True,
        has_key=True,
        test_success=success,
        test_message=message,
    )


@router.delete("/providers/{provider}")
async def remove_provider(provider: str, name: str = "default") -> Dict[str, Any]:
    """Remove a provider configuration."""
    manager = get_config_manager()
    success = manager.remove_provider(provider, name)

    if not success:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Provider {provider}:{name} not found"
        )

    return {"message": f"Removed {provider}:{name}"}


@router.post("/providers/{provider}/test", response_model=TestResult)
async def test_provider(provider: str, name: str = "default") -> TestResult:
    """Test provider credentials."""
    manager = get_config_manager()

    config = manager.get_provider(provider, name)
    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No configuration found for {provider}:{name}"
        )

    success, message = await manager.test_provider(provider, name)
    return TestResult(success=success, message=message)


# ── Project Endpoints ────────────────────────────────────────

@router.get("/providers/{provider}/projects", response_model=List[ExternalProjectResponse])
async def list_external_projects(
    provider: str,
    config_name: str = "default",
) -> List[ExternalProjectResponse]:
    """List projects from external provider."""
    manager = get_config_manager()
    config = manager.get_provider(provider, config_name)

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No configuration found for {provider}:{config_name}"
        )

    try:
        provider_instance = get_provider(
            config.provider,
            config.api_key,
            config.base_url,
            config.email,
        )
        async with provider_instance:
            projects = await provider_instance.list_projects()
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to list projects: {str(e)}"
        )

    return [
        ExternalProjectResponse(
            id=p.id,
            external_id=p.external_id,
            name=p.name,
            namespace=p.namespace,
            description=p.description,
            url=p.url,
            provider=p.provider,
        )
        for p in projects
    ]


@router.post("/providers/{provider}/projects", response_model=ExternalProjectResponse)
async def create_external_project(
    provider: str,
    request: CreateProjectRequest,
    config_name: str = "default",
) -> ExternalProjectResponse:
    """Create a project in external provider."""
    manager = get_config_manager()
    config = manager.get_provider(provider, config_name)

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No configuration found for {provider}:{config_name}"
        )

    try:
        provider_instance = get_provider(
            config.provider,
            config.api_key,
            config.base_url,
            config.email,
        )
        async with provider_instance:
            project = await provider_instance.create_project(
                request.name,
                request.description,
                request.namespace,
            )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create project: {str(e)}"
        )

    return ExternalProjectResponse(
        id=project.id,
        external_id=project.external_id,
        name=project.name,
        namespace=project.namespace,
        description=project.description,
        url=project.url,
        provider=project.provider,
    )


# ── Issue Endpoints ───────────────────────────────────────────

@router.get("/providers/{provider}/projects/{project_id}/issues", response_model=List[ExternalIssueResponse])
async def list_external_issues(
    provider: str,
    project_id: str,
    state: str = "all",
    config_name: str = "default",
) -> List[ExternalIssueResponse]:
    """List issues from external provider project."""
    manager = get_config_manager()
    config = manager.get_provider(provider, config_name)

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No configuration found for {provider}:{config_name}"
        )

    try:
        provider_instance = get_provider(
            config.provider,
            config.api_key,
            config.base_url,
            config.email,
        )
        async with provider_instance:
            issues = await provider_instance.list_issues(project_id, state)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to list issues: {str(e)}"
        )

    return [
        ExternalIssueResponse(
            id=i.id,
            number=i.number,
            title=i.title,
            description=i.description,
            state=i.state,
            url=i.url,
            labels=i.labels,
        )
        for i in issues
    ]


@router.post("/providers/{provider}/projects/{project_id}/issues", response_model=ExternalIssueResponse)
async def create_external_issue(
    provider: str,
    project_id: str,
    request: CreateIssueRequest,
    config_name: str = "default",
) -> ExternalIssueResponse:
    """Create an issue in external provider."""
    manager = get_config_manager()
    config = manager.get_provider(provider, config_name)

    if not config:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"No configuration found for {provider}:{config_name}"
        )

    try:
        provider_instance = get_provider(
            config.provider,
            config.api_key,
            config.base_url,
            config.email,
        )
        async with provider_instance:
            issue = await provider_instance.create_issue(
                project_id,
                request.title,
                request.description,
                request.labels,
            )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create issue: {str(e)}"
        )

    return ExternalIssueResponse(
        id=issue.id,
        number=issue.number,
        title=issue.title,
        description=issue.description,
        state=issue.state,
        url=issue.url,
        labels=issue.labels,
    )
