"""
alerte-event -- CLI de rappels de notifications (Telegram, Gmail, Discord).

Commandes :
    alerte-event              Menu interactif
    alerte-event config       Choisir et configurer un fournisseur
    alerte-event add          Planifier un evenement
    alerte-event list         Lister les evenements
    alerte-event delete <ID>  Supprimer un evenement
    alerte-event test         Envoyer une notification de test
    alerte-event scheduler    Lancer le demon
    alerte-event install-task Installer la tache Windows
"""
import sys
import uuid
import click
import questionary
from datetime import datetime
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich import box

from alerte_sms.config import (
    load_config, save_config, get_provider, set_provider,
    save_telegram_config, load_telegram_config,
    save_gmail_config, load_gmail_config,
    save_discord_config, load_discord_config,
    load_events, add_event, remove_event, CONFIG_DIR,
)
from alerte_sms.providers import (
    send_telegram, get_telegram_chat_id,
    send_gmail, send_discord,
)

console = Console()

FREQUENCIES = [
    "1 semaine avant",
    "3 jours avant",
    "1 jour avant",
    "12h avant",
    "1 heure avant",
    "Le jour meme",
]

PROVIDER_LABELS = {
    "telegram": "Telegram (gratuit, recommande)",
    "gmail":    "Gmail SMTP (gratuit, email)",
    "discord":  "Discord Webhook (gratuit)",
}


# ── Helpers ───────────────────────────────────────────────────────────────────

def check_config() -> dict | None:
    config = load_config()
    if not config.get("provider"):
        console.print(
            "\n[bold yellow]Aucun fournisseur configure.[/bold yellow]\n"
            "Lance [bold]alerte-event config[/bold] d'abord.\n"
        )
        return None
    return config


def validate_date(val: str) -> bool | str:
    try:
        dt = datetime.strptime(val.strip(), "%d/%m/%Y %H:%M")
        if dt <= datetime.now():
            return "La date doit etre dans le futur."
        return True
    except ValueError:
        return "Format invalide. Utilisez JJ/MM/AAAA HH:MM (ex: 25/12/2025 18:00)"


def collect_items(label: str, example: str, validator=None) -> list:
    """Boucle generique pour collecter plusieurs valeurs."""
    items = []
    console.print(f"\n[bold]Ajout des {label}[/bold]")
    if example:
        console.print(f"Exemple : [cyan]{example}[/cyan]")

    while True:
        val = questionary.text(
            f"  {label} {len(items)+1} (Entree pour terminer) :"
        ).ask()

        if not val:
            if not items:
                console.print("[red]Au moins une valeur est requise.[/red]")
                continue
            break

        val = val.strip()
        if validator:
            err = validator(val)
            if err:
                console.print(f"[red]{err}[/red]")
                continue

        items.append(val)
        console.print(f"  [green]OK[/green] {val} ajoute ({len(items)} au total)")

        if not questionary.confirm("  En ajouter un autre ?", default=False).ask():
            break

    return items


def validate_email(val: str) -> str | None:
    return None if "@" in val and "." in val else "Adresse email invalide."


def validate_webhook(val: str) -> str | None:
    return None if val.startswith("https://discord.com/api/webhooks/") else \
        "L'URL doit commencer par https://discord.com/api/webhooks/"


# ── Sous-commandes config par fournisseur ─────────────────────────────────────

def configure_telegram():
    console.print(Panel(
        "[bold]Configuration Telegram[/bold]\n\n"
        "1. Ouvre Telegram et cherche @BotFather\n"
        "2. Envoie /newbot et suis les instructions\n"
        "3. Copie le token donne par BotFather\n"
        "4. Envoie un message a ton bot, puis reviens ici",
        title="Telegram", expand=False
    ))

    existing = load_telegram_config()
    token = questionary.text(
        "Token du bot Telegram :",
        default=existing.get("token", ""),
    ).ask()

    if not token:
        console.print("[red]Annule.[/red]")
        return

    token = token.strip()
    console.print("\nRecuperation automatique du chat_id...")
    chat_id = get_telegram_chat_id(token)

    if chat_id:
        console.print(f"[green]Chat ID detecte : {chat_id}[/green]")
        use_auto = questionary.confirm(
            f"Utiliser ce chat_id ({chat_id}) ?", default=True
        ).ask()
        chat_ids = [chat_id] if use_auto else collect_items(
            "chat_id", "123456789"
        )
    else:
        console.print(
            "[yellow]Chat ID non detecte. Envoie d'abord un message a ton bot "
            "puis entre le chat_id manuellement.[/yellow]\n"
            "Astuce : envoie un message au bot, puis va sur :\n"
            "https://api.telegram.org/bot<TOKEN>/getUpdates"
        )
        chat_ids = collect_items("chat_id", "123456789")

    save_telegram_config(token, chat_ids)
    set_provider("telegram")
    console.print("\n[bold green]Configuration Telegram sauvegardee.[/bold green]")


def configure_gmail():
    console.print(Panel(
        "[bold]Configuration Gmail SMTP[/bold]\n\n"
        "Tu as besoin d'un mot de passe d'application Gmail,\n"
        "pas ton mot de passe Gmail habituel.\n\n"
        "Pour le creer :\n"
        "1. Va sur myaccount.google.com\n"
        "2. Securite > Verification en 2 etapes (active-la)\n"
        "3. Securite > Mots de passe des applications\n"
        "4. Cree un mot de passe pour 'Autre' et copie-le",
        title="Gmail", expand=False
    ))

    existing = load_gmail_config()
    address = questionary.text(
        "Ton adresse Gmail :",
        default=existing.get("address", ""),
    ).ask()

    app_password = questionary.password(
        "Mot de passe d'application (16 caracteres) :"
    ).ask()

    if not address or not app_password:
        console.print("[red]Annule.[/red]")
        return

    save_gmail_config(address.strip(), app_password.strip())
    set_provider("gmail")
    console.print("\n[bold green]Configuration Gmail sauvegardee.[/bold green]")


def configure_discord():
    console.print(Panel(
        "[bold]Configuration Discord Webhook[/bold]\n\n"
        "Pour creer un webhook :\n"
        "1. Ouvre ton serveur Discord\n"
        "2. Parametres du salon > Intégrations > Webhooks\n"
        "3. Cree un webhook et copie l'URL",
        title="Discord", expand=False
    ))

    existing = load_discord_config()
    default_urls = "\n".join(existing.get("webhook_urls", []))

    webhook_urls = collect_items(
        "webhook URL",
        "https://discord.com/api/webhooks/...",
        validator=validate_webhook,
    )

    save_discord_config(webhook_urls)
    set_provider("discord")
    console.print("\n[bold green]Configuration Discord sauvegardee.[/bold green]")


# ── Commandes Click ───────────────────────────────────────────────────────────

@click.group(invoke_without_command=True)
@click.pass_context
def main(ctx):
    """
    \b
    alerte-event -- Planificateur de rappels (Telegram, Gmail, Discord)
    """
    if ctx.invoked_subcommand is None:
        interactive_menu()


@main.command("config")
def cmd_config():
    """Choisir et configurer le fournisseur de notifications."""
    current = get_provider()
    if current:
        console.print(f"\nFournisseur actuel : [bold cyan]{current}[/bold cyan]")

    choice = questionary.select(
        "Quel fournisseur veux-tu utiliser ?",
        choices=list(PROVIDER_LABELS.values()),
    ).ask()

    # Retrouver la cle depuis le label
    provider = next(k for k, v in PROVIDER_LABELS.items() if v == choice)

    if provider == "telegram":
        configure_telegram()
    elif provider == "gmail":
        configure_gmail()
    elif provider == "discord":
        configure_discord()


@main.command("add")
def cmd_add():
    """Planifier un nouvel evenement."""
    config = check_config()
    if not config:
        sys.exit(1)

    provider = config["provider"]
    console.print(Panel(f"[bold cyan]Nouvel evenement[/bold cyan] via [bold]{provider}[/bold]", expand=False))

    name = questionary.text(
        "Nom de l'evenement :",
        validate=lambda v: True if v.strip() else "Le nom ne peut pas etre vide.",
    ).ask()

    date_str = questionary.text(
        "Date et heure (JJ/MM/AAAA HH:MM) :",
        validate=validate_date,
    ).ask()

    frequency = questionary.select(
        "Quand envoyer le rappel ?",
        choices=FREQUENCIES,
    ).ask()

    # Collecte des destinataires selon le fournisseur
    recipients = []
    if provider == "gmail":
        recipients = collect_items("adresse email", "ami@gmail.com", validate_email)

    # Confirmation
    dt = datetime.strptime(date_str.strip(), "%d/%m/%Y %H:%M")
    console.print("\n[bold]Recapitulatif :[/bold]")
    table = Table(box=box.ROUNDED, show_header=False)
    table.add_column("Champ", style="dim")
    table.add_column("Valeur", style="bold")
    table.add_row("Evenement", name)
    table.add_row("Date", dt.strftime("%d/%m/%Y a %H:%M"))
    table.add_row("Rappel", frequency)
    table.add_row("Fournisseur", provider)
    if recipients:
        table.add_row("Destinataires", "\n".join(recipients))
    console.print(table)

    if not questionary.confirm("\nConfirmer ?", default=True).ask():
        console.print("[yellow]Annule.[/yellow]")
        return

    event = {
        "id": str(uuid.uuid4())[:8],
        "name": name,
        "event_date": dt.isoformat(),
        "frequency": frequency,
        "recipients": recipients,
        "provider": provider,
        "created_at": datetime.now().isoformat(),
        "sent": False,
    }
    add_event(event)
    console.print(f"\n[bold green]Evenement planifie (ID: {event['id']})[/bold green]")
    console.print("[dim]Lance le scheduler : alerte-event install-task[/dim]")


@main.command("list")
def cmd_list():
    """Lister tous les evenements planifies."""
    events = load_events()
    if not events:
        console.print("[yellow]Aucun evenement planifie.[/yellow]")
        return

    table = Table(title="Evenements planifies", box=box.ROUNDED)
    table.add_column("ID", style="dim", width=10)
    table.add_column("Evenement", style="bold cyan")
    table.add_column("Date", style="green")
    table.add_column("Rappel")
    table.add_column("Via")
    table.add_column("Statut")

    for e in events:
        dt = datetime.fromisoformat(e["event_date"])
        status = "[green]Envoye[/green]" if e.get("sent") else "[yellow]En attente[/yellow]"
        table.add_row(
            e["id"],
            e["name"],
            dt.strftime("%d/%m/%Y %H:%M"),
            e["frequency"],
            e.get("provider", "?"),
            status,
        )
    console.print(table)


@main.command("delete")
@click.argument("event_id")
def cmd_delete(event_id):
    """Supprimer un evenement par son ID."""
    events = load_events()
    match = next((e for e in events if e["id"] == event_id), None)
    if not match:
        console.print(f"[red]Aucun evenement avec l'ID: {event_id}[/red]")
        sys.exit(1)

    if questionary.confirm(f"Supprimer '{match['name']}' ?", default=False).ask():
        remove_event(event_id)
        console.print(f"[green]Evenement {event_id} supprime.[/green]")
    else:
        console.print("[yellow]Annule.[/yellow]")


@main.command("test")
def cmd_test():
    """Envoyer une notification de test."""
    config = check_config()
    if not config:
        sys.exit(1)

    provider = config["provider"]
    message = "Test alerte-event -- Configuration OK !"
    console.print(f"\nEnvoi d'un test via [bold]{provider}[/bold]...")

    ok = False

    if provider == "telegram":
        cfg = load_telegram_config()
        results = send_telegram(cfg["token"], cfg["chat_ids"], message)
        ok = any(results.values())

    elif provider == "gmail":
        cfg = load_gmail_config()
        recipient = questionary.text("Email destinataire du test :").ask()
        results = send_gmail(
            cfg["address"], cfg["app_password"],
            [recipient.strip()],
            subject="Test alerte-event",
            message=message,
        )
        ok = any(results.values())

    elif provider == "discord":
        cfg = load_discord_config()
        results = send_discord(cfg["webhook_urls"], message)
        ok = any(results.values())

    if ok:
        console.print("[bold green]Notification envoyee avec succes.[/bold green]")
    else:
        console.print("[bold red]Echec. Verifie ta configuration.[/bold red]")


@main.command("scheduler")
def cmd_scheduler():
    """Lancer le demon de verification (premier plan)."""
    from alerte_sms.scheduler import run
    run()


@main.command("install-task")
def cmd_install_task():
    """Installer le scheduler comme tache Windows au demarrage."""
    import subprocess, shutil

    python_path = shutil.which("pythonw") or shutil.which("python")
    if not python_path:
        console.print("[red]Python introuvable dans le PATH.[/red]")
        sys.exit(1)

    import alerte_sms
    scheduler_script = str(
        Path(alerte_sms.__file__).parent / "scheduler.py"
    )

    cmd = [
        "schtasks", "/Create",
        "/TN", "AlerteEventScheduler",
        "/TR", f'"{python_path}" "{scheduler_script}"',
        "/SC", "ONLOGON",
        "/RL", "HIGHEST",
        "/F",
    ]

    try:
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            console.print(
                "\n[bold green]Tache 'AlerteEventScheduler' creee.[/bold green]\n"
                "Elle demarrera automatiquement a chaque connexion Windows.\n"
                "Pour la lancer maintenant : [bold]schtasks /Run /TN AlerteEventScheduler[/bold]"
            )
        else:
            console.print(f"[red]Erreur: {result.stderr}[/red]")
            console.print("[dim]Essaie en tant qu'Administrateur.[/dim]")
    except FileNotFoundError:
        console.print("[red]schtasks non disponible (Windows uniquement).[/red]")


@main.command("remove-task")
def cmd_remove_task():
    """Desinstaller la tache planifiee Windows."""
    import subprocess
    try:
        result = subprocess.run(
            ["schtasks", "/Delete", "/TN", "AlerteEventScheduler", "/F"],
            capture_output=True, text=True
        )
        console.print("[green]Tache supprimee.[/green]" if result.returncode == 0
                      else f"[red]{result.stderr}[/red]")
    except FileNotFoundError:
        console.print("[red]schtasks non disponible (Windows uniquement).[/red]")


# ── Menu interactif ───────────────────────────────────────────────────────────

def interactive_menu():
    action = questionary.select(
        "Que veux-tu faire ?",
        choices=[
            "Planifier un evenement",
            "Voir mes evenements",
            "Configurer le fournisseur",
            "Envoyer un test",
            "Installer le scheduler Windows",
            "Supprimer un evenement",
            "Quitter",
        ],
    ).ask()

    dispatch = {
        "Planifier un evenement":         cmd_add,
        "Voir mes evenements":            cmd_list,
        "Configurer le fournisseur":      cmd_config,
        "Envoyer un test":                cmd_test,
        "Installer le scheduler Windows": cmd_install_task,
        "Quitter":                        lambda: sys.exit(0),
    }

    if action == "Supprimer un evenement":
        events = load_events()
        if not events:
            console.print("[yellow]Aucun evenement a supprimer.[/yellow]")
            return
        choices = {f"{e['id']} -- {e['name']}": e["id"] for e in events}
        chosen = questionary.select("Lequel ?", choices=list(choices.keys())).ask()
        cmd_delete.callback(choices[chosen])
    else:
        fn = dispatch.get(action)
        if fn:
            fn.callback() if hasattr(fn, "callback") else fn()


if __name__ == "__main__":
    main()
