# app/api/v1/platform/signup.py
"""
Platform signup API endpoints.

Handles the multi-step signup flow:
1. Start signup (select tier + platform)
2. Create account (user + merchant)
3. Create store
4. Setup payment (collect card via SetupIntent)
5. Complete signup (create Stripe subscription with trial)

Platform-specific steps (e.g., OMS Letzshop claiming) are handled
by their respective modules and call into this core flow.

All endpoints are public (no authentication required).
"""

import logging

from fastapi import APIRouter, Depends, Response
from pydantic import BaseModel, EmailStr
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.environment import should_use_secure_cookies
from app.modules.billing.services.signup_service import signup_service

router = APIRouter()
logger = logging.getLogger(__name__)


# =============================================================================
# Request/Response Schemas
# =============================================================================


class SignupStartRequest(BaseModel):
    """Start signup - select tier and platform."""

    tier_code: str
    is_annual: bool = False
    platform_code: str
    language: str = "fr"


class SignupStartResponse(BaseModel):
    """Response from signup start."""

    session_id: str
    tier_code: str
    is_annual: bool
    platform_code: str


class CreateAccountRequest(BaseModel):
    """Create account (user + merchant)."""

    session_id: str
    email: EmailStr
    password: str
    first_name: str
    last_name: str
    merchant_name: str
    phone: str | None = None


class CreateAccountResponse(BaseModel):
    """Response from account creation (includes auto-created store)."""

    session_id: str
    user_id: int
    merchant_id: int
    stripe_customer_id: str
    store_id: int
    store_code: str


class CreateStoreRequest(BaseModel):
    """Create store for the merchant."""

    session_id: str
    store_name: str | None = None
    language: str | None = None


class CreateStoreResponse(BaseModel):
    """Response from store creation."""

    session_id: str
    store_id: int
    store_code: str


class SetupPaymentRequest(BaseModel):
    """Request payment setup."""

    session_id: str


class SetupPaymentResponse(BaseModel):
    """Response with Stripe SetupIntent client secret."""

    session_id: str
    client_secret: str
    stripe_customer_id: str


class CompleteSignupRequest(BaseModel):
    """Complete signup after card collection."""

    session_id: str
    setup_intent_id: str


class CompleteSignupResponse(BaseModel):
    """Response from signup completion."""

    success: bool
    store_code: str
    store_id: int
    redirect_url: str
    trial_ends_at: str
    access_token: str | None = None  # JWT token for automatic login


# =============================================================================
# Endpoints
# =============================================================================


@router.post("/signup/start", response_model=SignupStartResponse)  # public
async def start_signup(request: SignupStartRequest) -> SignupStartResponse:
    """
    Start the signup process.

    Step 1: User selects a tier, billing period, and platform.
    Creates a signup session to track the flow.
    """
    session_id = signup_service.create_session(
        tier_code=request.tier_code,
        is_annual=request.is_annual,
        platform_code=request.platform_code,
        language=request.language,
    )

    return SignupStartResponse(
        session_id=session_id,
        tier_code=request.tier_code,
        is_annual=request.is_annual,
        platform_code=request.platform_code,
    )


@router.post("/signup/create-account", response_model=CreateAccountResponse)  # public
async def create_account(
    request: CreateAccountRequest,
    db: Session = Depends(get_db),
) -> CreateAccountResponse:
    """
    Create user and merchant accounts.

    Step 2: User provides account details.
    Creates User, Merchant, and Stripe Customer.
    Store creation is a separate step.
    """
    result = signup_service.create_account(
        db=db,
        session_id=request.session_id,
        email=request.email,
        password=request.password,
        first_name=request.first_name,
        last_name=request.last_name,
        merchant_name=request.merchant_name,
        phone=request.phone,
    )

    return CreateAccountResponse(
        session_id=request.session_id,
        user_id=result.user_id,
        merchant_id=result.merchant_id,
        stripe_customer_id=result.stripe_customer_id,
        store_id=result.store_id,
        store_code=result.store_code,
    )


@router.post("/signup/create-store", response_model=CreateStoreResponse)  # public
async def create_store(
    request: CreateStoreRequest,
    db: Session = Depends(get_db),
) -> CreateStoreResponse:
    """
    Create the first store for the merchant.

    Step 3: User names their store (defaults to merchant name).
    Creates Store, StorePlatform, and MerchantSubscription.
    """
    result = signup_service.create_store(
        db=db,
        session_id=request.session_id,
        store_name=request.store_name,
        language=request.language,
    )

    return CreateStoreResponse(
        session_id=request.session_id,
        store_id=result.store_id,
        store_code=result.store_code,
    )


@router.post("/signup/setup-payment", response_model=SetupPaymentResponse)  # public
async def setup_payment(request: SetupPaymentRequest) -> SetupPaymentResponse:
    """
    Create Stripe SetupIntent for card collection.

    Step 4: Collect card details without charging.
    The card will be charged after the trial period ends.
    """
    client_secret, stripe_customer_id = signup_service.setup_payment(
        session_id=request.session_id,
    )

    return SetupPaymentResponse(
        session_id=request.session_id,
        client_secret=client_secret,
        stripe_customer_id=stripe_customer_id,
    )


@router.post("/signup/complete", response_model=CompleteSignupResponse)  # public
async def complete_signup(
    request: CompleteSignupRequest,
    response: Response,
    db: Session = Depends(get_db),
) -> CompleteSignupResponse:
    """
    Complete signup after card collection.

    Step 5: Verify SetupIntent, attach payment method, create subscription.
    Also sets HTTP-only cookie for page navigation and returns token for localStorage.
    """
    result = signup_service.complete_signup(
        db=db,
        session_id=request.session_id,
        setup_intent_id=request.setup_intent_id,
    )

    # Set HTTP-only cookie for page navigation (same as login does)
    # This enables the user to access store pages immediately after signup
    if result.access_token:
        response.set_cookie(
            key="store_token",
            value=result.access_token,
            httponly=True,  # JavaScript cannot access (XSS protection)
            secure=should_use_secure_cookies(),  # HTTPS only in production/staging
            samesite="lax",  # CSRF protection
            max_age=3600 * 24,  # 24 hours
            path="/store",  # RESTRICTED TO STORE ROUTES ONLY
        )
        logger.info(f"Set store_token cookie for new store {result.store_code}")

    return CompleteSignupResponse(
        success=result.success,
        store_code=result.store_code,
        store_id=result.store_id,
        redirect_url=result.redirect_url,
        trial_ends_at=result.trial_ends_at,
        access_token=result.access_token,
    )


@router.get("/signup/session/{session_id}")  # public
async def get_signup_session(session_id: str) -> dict:
    """
    Get signup session status.

    Useful for resuming an incomplete signup.
    """
    session = signup_service.get_session_or_raise(session_id)

    # Return safe subset of session data
    return {
        "session_id": session_id,
        "step": session.get("step"),
        "tier_code": session.get("tier_code"),
        "is_annual": session.get("is_annual"),
        "letzshop_slug": session.get("letzshop_slug"),
        "store_name": session.get("store_name"),
        "created_at": session.get("created_at"),
    }
