import typer
from pathlib import Path
from typing import Optional

from ..entities.agent import AgentRepository
from ..entities.agent_function import AgentFunctionRepository
from ..entities.agent_environment import AgentEnvironmentRepository
from ..entities.agent_phone_number_assignment import AgentPhoneNumberAssignmentRepository
from ..entities.agent_secret import AgentSecretRepository
from ..entities.organization_phone_number import OrganizationPhoneNumberRepository
from ..entities.organization_secret import OrganizationSecretRepository
from ..entities.organization_telephony import OrganizationTelephonyRepository
from ..entities.user import get_effective_organization_id
from ..utils.agent_lock import load_agent_lock
from ..utils.config import (
    ERROR_STYLE,
    SUCCESS_STYLE,
)
from ..utils.utils import console

app = typer.Typer(help="Delete resources.")


def _find_phone_number(repo, name_or_id):
    """Find a phone number by ID, phone number, or friendly name."""
    # Try by ID first
    pn = repo.get_by_id(name_or_id)
    if pn:
        return pn

    # Fall back to searching by phone_number or friendly_name
    phone_numbers = repo.get()
    for pn in phone_numbers:
        if pn.phone_number == name_or_id or pn.friendly_name == name_or_id:
            return pn

    return None


@app.command("assignment")
@app.command("assignments", hidden=True)
def delete_assignment(
    agent: str = typer.Argument(help="Agent name or ID"),
    assignment_id: str = typer.Argument(help="Assignment ID"),
):
    """Delete a phone number assignment from an agent."""
    # Resolve agent
    agent_repo = AgentRepository()
    agent_entity = agent_repo.get_by_name_or_id(agent)

    if not agent_entity:
        console.print(f"[{ERROR_STYLE}]Agent not found: {agent}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    repo = AgentPhoneNumberAssignmentRepository(agent_entity.id)
    success = repo.delete_by_id(assignment_id)

    if not success:
        console.print(f"[{ERROR_STYLE}]Failed to delete assignment '{assignment_id}'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    console.print(f"[{SUCCESS_STYLE}]Assignment '{assignment_id}' deleted successfully.[/{SUCCESS_STYLE}]")


@app.command("agent")
@app.command("agents", hidden=True)
def delete_agent(
    name_or_id: str = typer.Argument(help="Agent name or ID"),
):
    """Delete an agent."""
    repo = AgentRepository()
    agent = repo.get_by_name_or_id(name_or_id)

    if not agent:
        console.print(f"[{ERROR_STYLE}]Agent not found: {name_or_id}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    label = agent.name or agent.id
    success = repo.delete_by_id(agent.id)

    if not success:
        console.print(f"[{ERROR_STYLE}]Failed to delete agent '{label}'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    console.print(f"[{SUCCESS_STYLE}]Agent '{label}' deleted successfully.[/{SUCCESS_STYLE}]")


@app.command("function")
@app.command("functions", hidden=True)
def delete_function(
    agent: str = typer.Argument(help="Agent name or ID"),
    name_or_id: str = typer.Argument(help="Function name, display name, or ID"),
):
    """Delete a function from an agent."""
    agent_repo = AgentRepository()
    agent_entity = agent_repo.get_by_name_or_id(agent)

    if not agent_entity:
        console.print(f"[{ERROR_STYLE}]Agent not found: {agent}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    repo = AgentFunctionRepository(agent_entity.id)
    func = repo.get_by_name_or_id(name_or_id)

    if not func:
        console.print(f"[{ERROR_STYLE}]Function not found: {name_or_id}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    label = func.display_name or func.name or func.id
    success = repo.delete_by_id(func.id)

    if not success:
        console.print(f"[{ERROR_STYLE}]Failed to delete function '{label}'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    console.print(f"[{SUCCESS_STYLE}]Function '{label}' deleted successfully.[/{SUCCESS_STYLE}]")


@app.command("environment")
@app.command("environments", hidden=True)
def delete_environment(
    agent: str = typer.Argument(help="Agent name or ID"),
    name_or_id: str = typer.Argument(help="Environment name or ID"),
):
    """Delete an environment from an agent."""
    agent_repo = AgentRepository()
    agent_entity = agent_repo.get_by_name_or_id(agent)

    if not agent_entity:
        console.print(f"[{ERROR_STYLE}]Agent not found: {agent}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    repo = AgentEnvironmentRepository(agent_entity.id)
    env = repo.get_by_name_or_id(name_or_id)

    if not env:
        console.print(f"[{ERROR_STYLE}]Environment not found: {name_or_id}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    label = env.name or env.id
    success = repo.delete_by_id(env.id)

    if not success:
        console.print(f"[{ERROR_STYLE}]Failed to delete environment '{label}'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    console.print(f"[{SUCCESS_STYLE}]Environment '{label}' deleted successfully.[/{SUCCESS_STYLE}]")


@app.command("secret")
@app.command("secrets", hidden=True)
def delete_secret(
    name_or_id: str = typer.Argument(help="Secret name or ID"),
    agent: Optional[str] = typer.Option(None, "--agent", "-a", help="Agent name or ID"),
):
    """Delete a secret. Searches organization secrets first, then agent secrets."""
    organization_id = get_effective_organization_id()
    if not organization_id:
        console.print(f"[{ERROR_STYLE}]Unable to determine organization. Please sign in or set organization ID with 'vr context set-org'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    # Determine agent - from flag or from agent.lock
    agent_entity = None
    agent_id = None

    if agent:
        agent_repo = AgentRepository()
        agent_entity = agent_repo.get_by_name_or_id(agent)
        if not agent_entity:
            console.print(f"[{ERROR_STYLE}]Agent not found: {agent}[/{ERROR_STYLE}]")
            raise typer.Exit(1)
        agent_id = agent_entity.id
    else:
        voicerun_dir = Path.cwd() / ".voicerun"
        if voicerun_dir.exists():
            lock_data = load_agent_lock(voicerun_dir)
            if lock_data and "id" in lock_data:
                agent_id = lock_data["id"]
                agent_repo = AgentRepository()
                agent_entity = agent_repo.get_by_id(agent_id)

    # Try organization secrets first
    org_repo = OrganizationSecretRepository(organization_id)
    secret = org_repo.get_by_name_or_id(name_or_id)
    repo = org_repo

    # If not found at org level and we have an agent, try agent secrets
    if not secret and agent_id:
        agent_secret_repo = AgentSecretRepository(agent_id)
        secret = agent_secret_repo.get_by_name_or_id(name_or_id)
        repo = agent_secret_repo

    if not secret:
        console.print(f"[{ERROR_STYLE}]Secret not found: {name_or_id}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    label = secret.name or secret.id
    success = repo.delete_by_id(secret.id)

    if not success:
        console.print(f"[{ERROR_STYLE}]Failed to delete secret '{label}'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    console.print(f"[{SUCCESS_STYLE}]Secret '{label}' deleted successfully.[/{SUCCESS_STYLE}]")


@app.command("phonenumber")
@app.command("phonenumbers", hidden=True)
def delete_phone_number(
    name_or_id: str = typer.Argument(help="Phone number ID, phone number, or friendly name"),
    release: bool = typer.Option(False, "--release", help="Release the number back to the telephony provider"),
):
    """Delete an organization phone number."""
    organization_id = get_effective_organization_id()
    if not organization_id:
        console.print(f"[{ERROR_STYLE}]Unable to determine organization. Please sign in or set organization ID with 'vr context set-org'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    repo = OrganizationPhoneNumberRepository(organization_id)
    pn = _find_phone_number(repo, name_or_id)

    if not pn:
        console.print(f"[{ERROR_STYLE}]Phone number not found: {name_or_id}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    label = pn.phone_number or pn.friendly_name or pn.id

    if release:
        success = repo.release(pn.id)
        if not success:
            console.print(f"[{ERROR_STYLE}]Failed to release phone number '{label}'.[/{ERROR_STYLE}]")
            raise typer.Exit(1)
        console.print(f"[{SUCCESS_STYLE}]Phone number '{label}' released successfully.[/{SUCCESS_STYLE}]")
    else:
        success = repo.delete_by_id(pn.id)
        if not success:
            console.print(f"[{ERROR_STYLE}]Failed to delete phone number '{label}'.[/{ERROR_STYLE}]")
            raise typer.Exit(1)
        console.print(f"[{SUCCESS_STYLE}]Phone number '{label}' deleted successfully.[/{SUCCESS_STYLE}]")


@app.command("telephony")
def delete_telephony(
    name_or_id: str = typer.Argument(help="Telephony provider name or ID"),
):
    """Delete an organization telephony provider."""
    organization_id = get_effective_organization_id()
    if not organization_id:
        console.print(f"[{ERROR_STYLE}]Unable to determine organization. Please sign in or set organization ID with 'vr context set-org'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    repo = OrganizationTelephonyRepository(organization_id)
    provider = repo.get_by_name_or_id(name_or_id)

    if not provider:
        console.print(f"[{ERROR_STYLE}]Telephony provider not found: {name_or_id}[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    label = provider.name or provider.id
    success = repo.delete_by_id(provider.id)

    if not success:
        console.print(f"[{ERROR_STYLE}]Failed to delete telephony provider '{label}'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    console.print(f"[{SUCCESS_STYLE}]Telephony provider '{label}' deleted successfully.[/{SUCCESS_STYLE}]")


if __name__ == "__main__":
    app()
