"""
Kontosammenslåing ("Del 2" av flere-e-postadresser, ADR-080) -- selvbetjent:
initiativtakeren (en aktiv økt) ber om å slå en ANNEN, egen konto sammen med
den de er logget inn på. Krever bevis for eierskap av BEGGE kontoer: den
aktive økten beviser eierskap av initiativtakerens konto, en lenke sendt til
MÅL-kontoens e-post (samme token-i-lenke-mønster som ADR-032 sin e-postbytte)
beviser eierskap av den andre.

Selve beregningen/utførelsen ligger i app/account_merge.py (ren, uten
FastAPI-avhengigheter) -- denne filen er kun HTTP-laget: validering,
token-håndtering, e-postutsending.
"""

import secrets
import traceback
from datetime import datetime, timedelta, timezone

from fastapi import APIRouter, Depends
from pydantic import BaseModel, EmailStr

from ..account_merge import MergePreview, MergeResult, compute_merge_preview, execute_merge
from ..auth import CurrentUser, get_current_user, resolve_user_id_by_email
from ..config import settings
from ..db import plain_connection
from ..email import send_account_merge_confirmation
from ..errors import app_error
from .auth import _hash_secret

router = APIRouter(prefix="/auth/account-merge", tags=["account-merge"])


class AccountMergeEmailRequest(BaseModel):
    email: EmailStr


async def _resolve_target_or_error(conn, requester_id: str, email: str) -> str:
    target_id = await resolve_user_id_by_email(conn, email)
    if target_id is None:
        raise app_error(404, "NOT_FOUND", "Fant ingen konto med denne e-posten.")
    if target_id == requester_id:
        raise app_error(400, "VALIDATION_FAILED", "Dette er allerede din egen konto.")
    return target_id


@router.post("/preview", response_model=MergePreview)
async def preview_account_merge(
    body: AccountMergeEmailRequest, user: CurrentUser = Depends(get_current_user)
) -> MergePreview:
    async with plain_connection() as conn:
        target_id = await _resolve_target_or_error(conn, user.user_id, body.email.lower())
    return await compute_merge_preview(user.user_id, target_id)


@router.post("/request")
async def request_account_merge(
    body: AccountMergeEmailRequest, user: CurrentUser = Depends(get_current_user)
) -> dict:
    email = body.email.lower()
    async with plain_connection() as conn:
        target_id = await _resolve_target_or_error(conn, user.user_id, email)
        target_row = await conn.fetchrow(
            "SELECT email::text AS email, display_name FROM app_user WHERE id = $1", target_id
        )
        initiator_row = await conn.fetchrow(
            "SELECT display_name, email::text AS email FROM app_user WHERE id = $1", user.user_id
        )

        raw_token = secrets.token_urlsafe(32)
        expires_at = datetime.now(timezone.utc) + timedelta(minutes=settings.MAGIC_LINK_MAX_AGE_MINUTES)
        await conn.execute(
            "INSERT INTO account_merge_token (initiator_user_id, target_user_id, token_hash, expires_at) "
            "VALUES ($1, $2, $3, $4)",
            user.user_id,
            target_id,
            _hash_secret(raw_token),
            expires_at,
        )

    # Lenken sendes til MÅL-e-posten som faktisk ble oppgitt (kan være
    # taperens primær- ELLER en av dens sekundæradresser) -- beviser
    # eierskap av akkurat DEN adressen, tilstrekkelig siden begge allerede
    # er verifiserte adresser på taper-kontoen.
    if settings.DEV_LOG_MAGIC_LINKS:
        print(f"[DEV] Kontosammenslåing-lenke for {email}: {raw_token}", flush=True)
    elif settings.SMTP_CONFIGURED:
        try:
            await send_account_merge_confirmation(
                email, raw_token, initiator_row["display_name"], initiator_row["email"] or ""
            )
        except Exception:
            traceback.print_exc()
    return {"status": "ok", "detail": "Hvis e-posten tilhører en annen konto, er en bekreftelseslenke sendt."}


@router.get("/token/{token}", response_model=MergePreview)
async def get_account_merge_token(token: str) -> MergePreview:
    """Validerer token (IKKE konsumert/utløpt) og returnerer en FERSK
    forhåndsvisning -- konsumerer IKKE token, kun /confirm gjør det. Ingen
    sesjon påkrevd (samme som e-postbytte-bekreftelse, kan åpnes på en
    annen enhet enn den som ba om sammenslåingen)."""
    token_hash = _hash_secret(token)
    async with plain_connection() as conn:
        token_row = await conn.fetchrow(
            "SELECT initiator_user_id::text AS initiator_user_id, target_user_id::text AS target_user_id "
            "FROM account_merge_token WHERE token_hash = $1 AND consumed_at IS NULL AND expires_at > now()",
            token_hash,
        )
    if token_row is None:
        raise app_error(401, "INVALID_MERGE_LINK", "Lenken er ugyldig, brukt eller utløpt.")
    return await compute_merge_preview(token_row["initiator_user_id"], token_row["target_user_id"])


class AccountMergeConfirm(BaseModel):
    token: str


@router.post("/confirm", response_model=MergeResult)
async def confirm_account_merge(body: AccountMergeConfirm) -> MergeResult:
    token_hash = _hash_secret(body.token)
    async with plain_connection() as conn:
        # Atomisk forbruk: ÉN setning, ikke les-så-sjekk-så-skriv -- to
        # samtidige bekreftelser av samme lenke kan da ikke begge lykkes
        # (samme prinsipp som magic-link/e-postbytte).
        token_row = await conn.fetchrow(
            """
            UPDATE account_merge_token
            SET consumed_at = now()
            WHERE token_hash = $1 AND consumed_at IS NULL AND expires_at > now()
            RETURNING initiator_user_id::text AS initiator_user_id, target_user_id::text AS target_user_id
            """,
            token_hash,
        )
    if token_row is None:
        raise app_error(401, "INVALID_MERGE_LINK", "Lenken er ugyldig, brukt eller utløpt.")
    return await execute_merge(token_row["initiator_user_id"], token_row["target_user_id"])
