"""Core pipeline: list → fetch → write → delete."""

import sys
from pathlib import Path

from rich.console import Console
from rich.progress import (
    BarColumn,
    MofNCompleteColumn,
    Progress,
    SpinnerColumn,
    TextColumn,
    TimeElapsedColumn,
    TimeRemainingColumn,
)

from gmailarchiver.archive import open_archive
from gmailarchiver.gmail import (
    batch_delete,
    batch_trash,
    fetch_raw_message,
    list_message_ids,
)

console = Console(stderr=True)

_FLUSH_EVERY = 50      # write to disk every N messages
_DELETE_BATCH = 100    # collect N IDs before issuing a batchDelete


def run(
    service,
    year: int,
    output: Path,
    fmt: str = "mbox",
    delete: bool = True,
    trash: bool = False,
    dry_run: bool = False,
    label_ids: list[str] | None = None,
) -> int:
    """
    Archive all messages from *year* to *output*.

    Args:
        service:    Authenticated Gmail API service object.
        year:       Calendar year to archive (e.g. 2022).
        output:     Destination path (file for mbox, directory for maildir).
        fmt:        'mbox' or 'maildir'.
        delete:     Permanently delete messages after archiving.
        trash:      Move to Trash instead of permanent delete (overrides delete).
        dry_run:    List and count messages without downloading or deleting.
        label_ids:  Restrict to specific Gmail labels (None = all mail).

    Returns:
        Number of messages processed.
    """
    console.print(f"[bold]Scanning Gmail for messages in {year}…[/bold]")

    # ── Phase 1: collect all message IDs ────────────────────────────────────
    ids: list[str] = []
    with Progress(
        SpinnerColumn(),
        TextColumn("[progress.description]{task.description}"),
        TimeElapsedColumn(),
        console=console,
    ) as prog:
        task = prog.add_task("Listing messages…", total=None)
        for msg_id in list_message_ids(service, year, label_ids=label_ids):
            ids.append(msg_id)
            prog.update(task, description=f"Listing messages… [cyan]{len(ids):,}[/cyan] found")

    if not ids:
        console.print(f"[yellow]No messages found for {year}.[/yellow]")
        return 0

    console.print(f"Found [bold cyan]{len(ids):,}[/bold cyan] messages.")

    if dry_run:
        console.print("[yellow]Dry-run mode — no messages downloaded or deleted.[/yellow]")
        return len(ids)

    # ── Phase 2: download + write + (optionally) delete ─────────────────────
    pending_delete: list[str] = []
    failed: list[str] = []
    archived = 0

    action_label = "trash" if trash else ("delete" if delete else "keep")

    with open_archive(fmt, output) as arc:
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            BarColumn(),
            MofNCompleteColumn(),
            TimeElapsedColumn(),
            TextColumn("eta"),
            TimeRemainingColumn(),
            console=console,
        ) as prog:
            task = prog.add_task(
                f"Archiving → {output.name}  [{action_label} after]",
                total=len(ids),
            )

            for msg_id in ids:
                try:
                    raw = fetch_raw_message(service, msg_id)
                    arc.add(raw)
                    archived += 1
                    pending_delete.append(msg_id)
                except Exception as exc:
                    console.print(f"\n[red]Error fetching {msg_id}: {exc}[/red]")
                    failed.append(msg_id)

                # Flush archive and batch-delete periodically
                if archived % _FLUSH_EVERY == 0:
                    arc.flush()

                if delete and not trash and len(pending_delete) >= _DELETE_BATCH:
                    _do_delete(service, pending_delete, trash=False)
                    pending_delete.clear()
                elif trash and len(pending_delete) >= _DELETE_BATCH:
                    _do_delete(service, pending_delete, trash=True)
                    pending_delete.clear()

                prog.advance(task)

        # Final flush + leftover deletions
        arc.flush()

    if pending_delete:
        if delete or trash:
            _do_delete(service, pending_delete, trash=trash)

    # ── Summary ──────────────────────────────────────────────────────────────
    console.print()
    console.print(f"[bold green]✓ Archived {archived:,} messages[/bold green] → {output}")
    if failed:
        console.print(f"[bold red]✗ {len(failed)} messages failed — IDs written to failed.txt[/bold red]")
        Path("failed.txt").write_text("\n".join(failed))
    if delete or trash:
        verb = "trashed" if trash else "permanently deleted"
        console.print(f"[bold]{archived:,} messages {verb} from Gmail.[/bold]")

    return archived


def _do_delete(service, ids: list[str], trash: bool) -> None:
    try:
        if trash:
            batch_trash(service, ids)
        else:
            batch_delete(service, ids)
    except Exception as exc:
        console.print(f"[red]Delete batch failed: {exc}[/red]")
