"""
User Profile Celery Tasks — PRD-006

Covers:
  - Email-change confirmation email
  - Password-changed security notification
  - New-login notification
  - Nightly cleanup of expired (unconfirmed) email-change tokens

All tasks are stubbed. Replace the placeholder comments with real email-service
calls once the SMTP / SendGrid credentials are confirmed by DevOps.

Beat schedule registration is in src/worker/config.py:
  "user-profile-cleanup-expired-email-tokens": crontab(hour=2, minute=0)
"""

import logging
from typing import Any, Dict

from celery.utils.log import get_task_logger
from src.worker.celery_app import celery_app

logger = get_task_logger(__name__)


# ──────────────────────────────────────────────────────────────────────────────
# Email-Change Confirmation
# ──────────────────────────────────────────────────────────────────────────────

@celery_app.task(
    bind=True,
    name="user_profile.send_email_change_confirmation",
    max_retries=3,
    default_retry_delay=60,
)
def send_email_change_confirmation(
    self,
    user_id: str,
    new_email: str,
    raw_token: str,
    user_name: str,
) -> Dict[str, Any]:
    """
    Send an email-change confirmation link to the user's NEW address.

    The confirmation link must include `raw_token` as a query param. The token
    is one-time-use; the backend stores only its SHA-256 hash.

    Args:
        user_id:    UUID of the user requesting the change.
        new_email:  The new email address to send the confirmation to.
        raw_token:  Plain-text token (NOT the hash). Include in the link as-is.
        user_name:  Display name for the greeting line.

    Returns:
        dict with task_id and delivery status.
    """
    try:
        logger.info(
            "Sending email-change confirmation to %s for user %s",
            new_email,
            user_id,
        )

        # TODO: Replace with real email-service call, e.g.:
        #   from src.core.email import send_transactional_email
        #   send_transactional_email(
        #       to=new_email,
        #       template="email_change_confirmation",
        #       context={"user_name": user_name, "token": raw_token},
        #   )

        logger.info("Email-change confirmation sent to %s (stub)", new_email)
        return {"task_id": self.request.id, "status": "sent_stub", "recipient": new_email}

    except Exception as exc:
        logger.error("send_email_change_confirmation failed: %s", exc)
        raise self.retry(exc=exc)


# ──────────────────────────────────────────────────────────────────────────────
# Password-Changed Security Notification
# ──────────────────────────────────────────────────────────────────────────────

@celery_app.task(
    bind=True,
    name="user_profile.send_password_changed_notification",
    max_retries=3,
    default_retry_delay=60,
)
def send_password_changed_notification(
    self,
    user_id: str,
    merchant_id: str,
) -> Dict[str, Any]:
    """
    Notify the user that their password was changed successfully.

    Triggered immediately after a successful PUT /api/v1/users/me/password.
    If the user did NOT initiate the change they should be prompted to contact
    support via the email body.

    Args:
        user_id:     UUID of the user whose password changed.
        merchant_id: Merchant UUID (used to look up contact/branding details).

    Returns:
        dict with task_id and delivery status.
    """
    try:
        logger.info(
            "Sending password-changed notification for user %s (merchant %s)",
            user_id,
            merchant_id,
        )

        # TODO: Fetch user email from DB and send:
        #   from src.core.email import send_transactional_email
        #   send_transactional_email(
        #       to=user_email,
        #       template="password_changed",
        #       context={"user_name": ..., "merchant_name": ...},
        #   )

        logger.info("Password-changed notification sent for user %s (stub)", user_id)
        return {"task_id": self.request.id, "status": "sent_stub", "user_id": user_id}

    except Exception as exc:
        logger.error("send_password_changed_notification failed: %s", exc)
        raise self.retry(exc=exc)


# ──────────────────────────────────────────────────────────────────────────────
# New-Login Notification
# ──────────────────────────────────────────────────────────────────────────────

@celery_app.task(
    bind=True,
    name="user_profile.send_new_login_notification",
    max_retries=3,
    default_retry_delay=60,
)
def send_new_login_notification(
    self,
    user_id: str,
    merchant_id: str,
    session_id: str,
) -> Dict[str, Any]:
    """
    Notify the user that a new login session was created from an unrecognised
    device or location.

    The email should include geo/device metadata from the auth_sessions row so
    the user can identify whether the login is legitimate.

    Args:
        user_id:     UUID of the authenticated user.
        merchant_id: Merchant UUID for branding/contact lookup.
        session_id:  UUID of the newly created auth_session row.

    Returns:
        dict with task_id and delivery status.
    """
    try:
        logger.info(
            "Sending new-login notification for user %s session %s",
            user_id,
            session_id,
        )

        # TODO: Fetch session geo/device details from auth_sessions by session_id.
        # TODO: Send transactional email with device/location context.

        logger.info("New-login notification sent for user %s (stub)", user_id)
        return {
            "task_id": self.request.id,
            "status": "sent_stub",
            "user_id": user_id,
            "session_id": session_id,
        }

    except Exception as exc:
        logger.error("send_new_login_notification failed: %s", exc)
        raise self.retry(exc=exc)


# ──────────────────────────────────────────────────────────────────────────────
# Nightly Cleanup — Expired Email-Change Tokens
# ──────────────────────────────────────────────────────────────────────────────

@celery_app.task(
    name="user_profile.cleanup_expired_email_change_tokens",
    max_retries=2,
    default_retry_delay=300,
)
def cleanup_expired_email_change_tokens() -> Dict[str, Any]:
    """
    Delete EmailChangeRequest rows that are unconfirmed and older than 7 days.

    Scheduled via Celery Beat at 02:00 UTC daily (see src/worker/config.py).
    This prevents unbounded growth of the email_change_requests table.

    Returns:
        dict with the number of rows deleted.
    """
    try:
        from datetime import datetime, timedelta, timezone

        from sqlalchemy import delete

        from src.core.database import SessionCelery
        from src.apps.user_profile.models.email_change_request import EmailChangeRequest

        cutoff = datetime.now(tz=timezone.utc) - timedelta(days=7)

        with SessionCelery() as db:
            stmt = delete(EmailChangeRequest).where(
                EmailChangeRequest.confirmed_at.is_(None),
                EmailChangeRequest.created_at < cutoff,
            )
            result = db.execute(stmt)
            deleted = result.rowcount
            db.commit()

        logger.info("cleanup_expired_email_change_tokens: deleted %d rows", deleted)
        return {"status": "ok", "deleted_count": deleted}

    except Exception as exc:
        logger.error("cleanup_expired_email_change_tokens failed: %s", exc)
        raise


# ──────────────────────────────────────────────────────────────────────────────
# Exports
# ──────────────────────────────────────────────────────────────────────────────

__all__ = [
    "send_email_change_confirmation",
    "send_password_changed_notification",
    "send_new_login_notification",
    "cleanup_expired_email_change_tokens",
]
