"""Google OAuth CLI commands — unified auth for Calendar + Gmail."""

import os
import time
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs, urlencode, urlparse

import httpx
import typer

from fliiq.cli import display
from fliiq.runtime.google_auth import TOKENS_PATH, load_tokens, save_tokens

google_app = typer.Typer(help="Google account integration (Calendar + Gmail)")

SCOPES = (
    "https://www.googleapis.com/auth/calendar "
    "https://www.googleapis.com/auth/userinfo.email "
    "https://mail.google.com/"
)
REDIRECT_URI = "http://localhost:8080/callback"


@google_app.command("auth")
def auth():
    """Authorize a Google account for Calendar + Gmail access. Run once per account."""
    client_id = os.environ.get("GOOGLE_CLIENT_ID")
    client_secret = os.environ.get("GOOGLE_CLIENT_SECRET")

    if not client_id or not client_secret:
        display.print_error(
            "Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in your .env file first.\n"
            "Create OAuth credentials at https://console.cloud.google.com/apis/credentials"
        )
        raise typer.Exit(1)

    auth_url = (
        "https://accounts.google.com/o/oauth2/v2/auth?"
        + urlencode({
            "client_id": client_id,
            "redirect_uri": REDIRECT_URI,
            "response_type": "code",
            "scope": SCOPES,
            "access_type": "offline",
            "prompt": "consent",
        })
    )

    auth_code = None
    auth_error = None

    class _CallbackHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            nonlocal auth_code, auth_error
            qs = parse_qs(urlparse(self.path).query)
            auth_code = qs.get("code", [None])[0]
            auth_error = qs.get("error", [None])[0]
            self.send_response(200)
            self.end_headers()
            if auth_error:
                self.wfile.write(f"Authorization failed: {auth_error}".encode())
            else:
                self.wfile.write(b"Success! You can close this tab.")

        def log_message(self, format, *args):
            pass  # Suppress HTTP server logs

    typer.echo("Opening browser for Google OAuth consent...")
    typer.echo(f"If the browser doesn't open, visit:\n{auth_url}\n")

    try:
        server = HTTPServer(("localhost", 8080), _CallbackHandler)
    except OSError as e:
        display.print_error(f"Could not start local server on port 8080: {e}")
        raise typer.Exit(1)

    webbrowser.open(auth_url)
    server.handle_request()

    if auth_error:
        display.print_error(f"Authorization failed: {auth_error}")
        raise typer.Exit(1)

    if not auth_code:
        display.print_error("No authorization code received. Try again.")
        raise typer.Exit(1)

    # Exchange code for tokens
    typer.echo("Exchanging authorization code for tokens...")
    resp = httpx.post(
        "https://oauth2.googleapis.com/token",
        data={
            "code": auth_code,
            "client_id": client_id,
            "client_secret": client_secret,
            "redirect_uri": REDIRECT_URI,
            "grant_type": "authorization_code",
        },
        timeout=30,
    )

    if resp.status_code != 200:
        display.print_error(f"Token exchange failed: {resp.text}")
        raise typer.Exit(1)

    tokens = resp.json()
    if "refresh_token" not in tokens:
        display.print_error(
            "No refresh token received. Revoke access at "
            "https://myaccount.google.com/permissions and try again."
        )
        raise typer.Exit(1)

    # Get the account email via userinfo
    access_token = tokens["access_token"]
    userinfo_resp = httpx.get(
        "https://www.googleapis.com/oauth2/v1/userinfo",
        headers={"Authorization": f"Bearer {access_token}"},
        timeout=30,
    )

    if userinfo_resp.status_code != 200:
        display.print_error(f"Failed to get account info: {userinfo_resp.text}")
        raise typer.Exit(1)

    account_email = userinfo_resp.json().get("email", "unknown")

    # Store tokens
    all_tokens = load_tokens()
    all_tokens[account_email] = {
        "access_token": tokens["access_token"],
        "refresh_token": tokens["refresh_token"],
        "expires_at": time.time() + tokens.get("expires_in", 3600) - 60,
    }
    save_tokens(all_tokens)

    typer.echo(f"Authorized Google account: {account_email} (Calendar + Gmail)")
    typer.echo(f"Token saved to {TOKENS_PATH}")

    # Auto-add email to user.yaml if not already present
    _maybe_add_to_user_profile(account_email)


def _maybe_add_to_user_profile(email: str) -> None:
    """Prompt to add an OAuth'd email to ~/.fliiq/user.yaml if not already there."""
    import yaml

    from fliiq.runtime.config import global_fliiq_dir

    user_yaml_path = global_fliiq_dir() / "user.yaml"

    # Load existing profile
    profile: dict = {}
    if user_yaml_path.is_file():
        try:
            data = yaml.safe_load(user_yaml_path.read_text())
            if isinstance(data, dict):
                profile = data
        except Exception:
            pass

    # Check if email already present
    existing_emails = [
        e.get("address", "").lower()
        for e in profile.get("emails", [])
        if isinstance(e, dict)
    ]
    if email.lower() in existing_emails:
        return  # Already tracked

    # Prompt user
    add = typer.confirm(f"Add {email} to your user profile (~/.fliiq/user.yaml)?", default=True)
    if not add:
        return

    label = typer.prompt("Label (e.g. personal, work, family)", default="personal")

    # Append to emails list
    if "emails" not in profile or not isinstance(profile.get("emails"), list):
        profile["emails"] = []
    profile["emails"].append({"address": email, "label": label})

    # Write back
    user_yaml_path.parent.mkdir(parents=True, exist_ok=True)
    user_yaml_path.write_text(yaml.dump(profile, default_flow_style=False, sort_keys=False))
    typer.echo(f"Added {email} ({label}) to {user_yaml_path}")


@google_app.command("accounts")
def accounts():
    """List authorized Google accounts."""
    all_tokens = load_tokens()

    if not all_tokens:
        typer.echo("No accounts authorized yet. Run `fliiq google auth` to get started.")
        return

    typer.echo("Authorized Google accounts:")
    for email in all_tokens:
        typer.echo(f"  - {email}")
