package web

import (
	"net/http"

	"git.d-ma.be/mathias/tapir/internal/adapters/store"
)

// handleAccount renders the account page: the user's display name, the
// authenticated email, their connected video accounts (with a Connect link when
// YouTube is not connected), and the disconnect / delete-account controls.
func (a *App) handleAccount(w http.ResponseWriter, r *http.Request) {
	userID, ok := a.currentUserID(w, r)
	if !ok {
		return
	}
	conns, err := a.Store.ConnectionsForUser(r.Context(), userID)
	if err != nil {
		a.serverError(w, r, "list connections", err)
		return
	}
	name, err := a.Store.DisplayName(r.Context(), userID)
	if err != nil {
		a.serverError(w, r, "display name", err)
		return
	}
	var email string
	if u, ok := a.Auth.CurrentUser(r); ok {
		email = u.Email
	}
	auto, err := a.Store.GetAutoSummarize(r.Context(), userID)
	if err != nil {
		a.serverError(w, r, "summarize mode", err)
		return
	}
	channelErrs, err := a.Store.ListChannelErrors(r.Context(), userID)
	if err != nil {
		a.serverError(w, r, "channel errors", err)
		return
	}
	a.render(w, r, AccountPage(name, email, conns, auto, channelErrs, takeFlash(w, r)))
}

// handleDisconnect removes a provider connection: it deletes the OAuth token from
// the SecretStore (resolved from the connection's own token_ref) and the
// connection row. It does NOT delete the account. Redirects back to /account with
// a flash. Disconnecting an absent provider is a no-op (idempotent).
func (a *App) handleDisconnect(w http.ResponseWriter, r *http.Request) {
	userID, ok := a.currentUserID(w, r)
	if !ok {
		return
	}
	provider := r.PathValue("provider")
	if provider == "" {
		http.Error(w, "missing provider", http.StatusBadRequest)
		return
	}

	conns, err := a.Store.ConnectionsForUser(r.Context(), userID)
	if err != nil {
		a.serverError(w, r, "list connections", err)
		return
	}
	// Remove the token before the row, using the connection's own ref so this is
	// provider-agnostic. A SecretStore failure is logged, not fatal — the row
	// removal below still revokes access from Tapir's side.
	if ref := tokenRefFor(conns, provider); ref != "" && a.Secrets != nil {
		if err := a.Secrets.Delete(ref); err != nil {
			a.logger().Error("disconnect: delete token", "provider", provider, "err", err)
		}
	}
	if err := a.Store.DeleteConnection(r.Context(), userID, provider); err != nil {
		a.serverError(w, r, "delete connection", err)
		return
	}

	setFlash(w, flashDisconnected)
	http.Redirect(w, r, "/account", http.StatusSeeOther)
}

// handleDeleteAccount permanently deletes the user: it removes all tapir data
// (DeleteUser cascades the rows) and every one of the user's secrets, then logs
// the user out. Tapir-side only (decision 2026-06-03) — the Dex identity is left
// untouched, so a later login simply re-enters registration.
func (a *App) handleDeleteAccount(w http.ResponseWriter, r *http.Request) {
	userID, ok := a.currentUserID(w, r)
	if !ok {
		return
	}

	// Capture the secret refs BEFORE the rows are deleted — DeleteUser cascades
	// the video_connections away.
	conns, err := a.Store.ConnectionsForUser(r.Context(), userID)
	if err != nil {
		a.serverError(w, r, "list connections", err)
		return
	}
	if err := a.Store.DeleteUser(r.Context(), userID); err != nil {
		a.serverError(w, r, "delete user", err)
		return
	}
	// Best-effort secret cleanup: the account is already gone, so a SecretStore
	// failure is logged, never resurrects the account.
	if a.Secrets != nil {
		for _, c := range conns {
			if c.TokenRef == "" {
				continue
			}
			if err := a.Secrets.Delete(c.TokenRef); err != nil {
				a.logger().Error("delete account: delete token", "ref", c.TokenRef, "err", err)
			}
		}
	}

	// Clear the session by routing through the auth logout endpoint, then land on
	// the list page with a flash (StubAuth logout is a no-op; Dex clears the
	// session cookie and redirects to login).
	setFlash(w, flashDeleted)
	http.Redirect(w, r, "/auth/logout", http.StatusSeeOther)
}

// tokenRefFor returns the SecretStore ref for the user's connection to provider,
// or "" if there is none.
func tokenRefFor(conns []store.Connection, provider string) string {
	for _, c := range conns {
		if c.Provider == provider {
			return c.TokenRef
		}
	}
	return ""
}
