"""Promotion of pending registrations to users on first email verify."""
from __future__ import annotations
from typing import Optional
from uuid import UUID

from src.config import Settings, get_settings
from src.domain.auth.models import PendingRegistration, User
from src.domain.auth.repository import (
    PendingRegistrationRepository,
    UserRepository,
)
from src.domain.billing.constants import STAFF_PLAN_SLUG
from src.domain.billing.credit_policy import email_is_staff
from src.domain.workspaces.repository import (
    MembershipRepository,
    RoleRepository,
    WorkspaceInviteRepository,
    WorkspaceRepository,
    WorkspaceSettingsRepository,
)
from src.domain.workspaces.service import slugify

# Imported lazily to avoid circular deps with billing domain
_StripeCustomerRepository = None
_SubscriptionRepository = None


class PromotionService:
    """Promotes pending registration to user + workspace."""

    def __init__(
        self,
        pending_repo: PendingRegistrationRepository,
        user_repo: UserRepository,
        workspace_repo: WorkspaceRepository,
        membership_repo: MembershipRepository,
        role_repo: RoleRepository,
        invite_repo: WorkspaceInviteRepository,
        settings_repo: WorkspaceSettingsRepository,
        settings: Optional[Settings] = None,
        stripe_customer_repo=None,
        subscription_repo=None,
    ):
        self._pending_repo = pending_repo
        self._user_repo = user_repo
        self._workspace_repo = workspace_repo
        self._membership_repo = membership_repo
        self._role_repo = role_repo
        self._invite_repo = invite_repo
        self._settings_repo = settings_repo
        self._settings = settings or get_settings()
        self._stripe_customer_repo = stripe_customer_repo
        self._subscription_repo = subscription_repo

    async def promote(self, pending: PendingRegistration) -> User:
        """
        Promote pending registration to user + workspace.
        Invite-first: if user has pending invites, do not create workspace.
        Staff emails (matching STAFF_EMAIL_DOMAINS) are auto-assigned the staff plan
        with quota limits disabled.
        """
        user = await self._user_repo.create(
            email=pending.email,
            first_name=pending.first_name,
            last_name=pending.last_name,
            phone=pending.phone,
            company=pending.company,
        )
        await self._user_repo.update_email_verified(user.id)

        has_pending_invites = await self._invite_repo.has_pending_invite_for_email(pending.email)
        workspaces = await self._workspace_repo.list_for_user(user.id)

        if not workspaces and not has_pending_invites:
            name = (
                pending.workspace_name
                or pending.company
                or f"{pending.first_name or ''} {pending.last_name or ''}".strip()
                or pending.email.split("@")[0]
            ).strip()[:255]
            base_slug = slugify(name)
            slug = base_slug
            counter = 0
            while await self._workspace_repo.slug_exists(slug):
                counter += 1
                slug = f"{base_slug}-{counter}"
            owner_role = await self._role_repo.get_or_create_system_role("owner")

            is_staff = email_is_staff(pending.email, self._settings.staff_email_domain_set)
            plan_slug = STAFF_PLAN_SLUG if is_staff else pending.plan_slug

            ws = await self._workspace_repo.create(
                slug=slug,
                name=name or "My Workspace",
                owner_id=user.id,
                selected_plan_slug=plan_slug,
                onboarding_status="pending_verification",
                skip_plan_quota_limits=is_staff,
            )
            await self._membership_repo.create(
                workspace_id=ws.id,
                user_id=user.id,
                role_id=owner_role.id,
                invited_by=None,
            )
            await self._settings_repo.get_or_create(ws.id)

            # If user paid via the home site before verifying email, link their
            # existing Stripe customer and subscription to the new workspace.
            if pending.stripe_customer_id and self._stripe_customer_repo:
                await self._stripe_customer_repo.create(ws.id, pending.stripe_customer_id)

            if pending.stripe_subscription_id and self._subscription_repo:
                await self._subscription_repo.upsert_from_stripe(
                    ws.id,
                    {
                        "id": pending.stripe_subscription_id,
                        "customer": pending.stripe_customer_id,
                        "status": "active",
                        "plan_slug": plan_slug,
                    },
                )

        await self._pending_repo.delete(pending.id)
        return await self._user_repo.get_by_id(user.id)
