import json
from typing import Optional

from sqlalchemy import select, update
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.pre_test_template import PreTestTemplate
from app.utils.id_gen import generate_id


async def create_pre_test_template(
    user_id: str,
    db: AsyncSession,
    name: str,
    note: Optional[str] = None,
    platform: Optional[str] = None,
    external_action: Optional[str] = None,
    cpa_bid: Optional[float] = None,
    audience_gender: Optional[str] = None,
    audience_age: Optional[list] = None,
    audience_region: Optional[list] = None,
    audience_network: Optional[list] = None,
    cus_name: Optional[str] = None,
    pricing_type: Optional[str] = None,
    cost_cap: Optional[bool] = None,
    target_cost: Optional[bool] = None,
    nobid: Optional[bool] = None,
    cpc_bid: Optional[float] = None,
    budget: Optional[float] = None,
    is_default: Optional[bool] = None,
) -> PreTestTemplate:
    if is_default:
        await db.execute(
            update(PreTestTemplate)
            .where(
                PreTestTemplate.user_id == user_id,
                PreTestTemplate.is_default == True,
                PreTestTemplate.deleted_at.is_(None),
            )
            .values(is_default=False)
        )

    template = PreTestTemplate(
        id=generate_id(),
        user_id=user_id,
        name=name,
        note=note,
        platform=platform,
        external_action=external_action,
        cpa_bid=cpa_bid,
        audience_gender=audience_gender,
        audience_age=json.dumps(audience_age) if audience_age else None,
        audience_region=json.dumps(audience_region) if audience_region else None,
        audience_network=json.dumps(audience_network) if audience_network else None,
        cus_name=cus_name,
        pricing_type=pricing_type,
        cost_cap=cost_cap,
        target_cost=target_cost,
        nobid=nobid,
        cpc_bid=cpc_bid,
        budget=budget,
        is_default=is_default,
    )

    db.add(template)
    await db.commit()
    await db.refresh(template)
    return template


async def update_pre_test_template(
    template_id: str,
    user_id: str,
    db: AsyncSession,
    **kwargs,
) -> Optional[PreTestTemplate]:
    result = await db.execute(
        select(PreTestTemplate).where(
            PreTestTemplate.id == template_id,
            PreTestTemplate.user_id == user_id,
            PreTestTemplate.deleted_at.is_(None),
        )
    )
    template = result.scalar_one_or_none()

    if not template:
        return None

    if kwargs.get("is_default"):
        await db.execute(
            update(PreTestTemplate)
            .where(
                PreTestTemplate.user_id == user_id,
                PreTestTemplate.is_default == True,
                PreTestTemplate.id != template_id,
                PreTestTemplate.deleted_at.is_(None),
            )
            .values(is_default=False)
        )

    update_data = {}
    if "name" in kwargs:
        update_data["name"] = kwargs["name"]
    if "note" in kwargs:
        update_data["note"] = kwargs["note"]
    if "platform" in kwargs:
        update_data["platform"] = kwargs["platform"]
    if "external_action" in kwargs:
        update_data["external_action"] = kwargs["external_action"]
    if "cpa_bid" in kwargs:
        update_data["cpa_bid"] = kwargs["cpa_bid"]
    if "audience_gender" in kwargs:
        update_data["audience_gender"] = kwargs["audience_gender"]
    if "audience_age" in kwargs:
        update_data["audience_age"] = json.dumps(kwargs["audience_age"]) if kwargs["audience_age"] else None
    if "audience_region" in kwargs:
        update_data["audience_region"] = json.dumps(kwargs["audience_region"]) if kwargs["audience_region"] else None
    if "audience_network" in kwargs:
        update_data["audience_network"] = json.dumps(kwargs["audience_network"]) if kwargs["audience_network"] else None
    if "cus_name" in kwargs:
        update_data["cus_name"] = kwargs["cus_name"]
    if "pricing_type" in kwargs:
        update_data["pricing_type"] = kwargs["pricing_type"]
    if "cost_cap" in kwargs:
        update_data["cost_cap"] = kwargs["cost_cap"]
    if "target_cost" in kwargs:
        update_data["target_cost"] = kwargs["target_cost"]
    if "nobid" in kwargs:
        update_data["nobid"] = kwargs["nobid"]
    if "cpc_bid" in kwargs:
        update_data["cpc_bid"] = kwargs["cpc_bid"]
    if "budget" in kwargs:
        update_data["budget"] = kwargs["budget"]
    if "is_default" in kwargs:
        update_data["is_default"] = kwargs["is_default"]

    if update_data:
        await db.execute(
            update(PreTestTemplate)
            .where(PreTestTemplate.id == template_id)
            .values(**update_data)
        )
        await db.commit()
        await db.refresh(template)

    return template


async def delete_pre_test_template(
    template_id: str,
    user_id: str,
    db: AsyncSession,
) -> bool:
    result = await db.execute(
        select(PreTestTemplate).where(
            PreTestTemplate.id == template_id,
            PreTestTemplate.user_id == user_id,
            PreTestTemplate.deleted_at.is_(None),
        )
    )
    template = result.scalar_one_or_none()

    if not template:
        return False

    from datetime import datetime
    template.deleted_at = datetime.now()
    await db.commit()
    return True


async def get_pre_test_template(
    template_id: str,
    user_id: str,
    db: AsyncSession,
) -> Optional[PreTestTemplate]:
    result = await db.execute(
        select(PreTestTemplate).where(
            PreTestTemplate.id == template_id,
            PreTestTemplate.user_id == user_id,
            PreTestTemplate.deleted_at.is_(None),
        )
    )
    return result.scalar_one_or_none()


async def get_pre_test_template_list(
    user_id: str,
    db: AsyncSession,
    platform: Optional[str] = None,
    page: int = 1,
    page_size: int = 10,
) -> dict:
    if page < 1:
        page = 1
    if page_size < 1:
        page_size = 10
    if page_size > 100:
        page_size = 100

    query = select(PreTestTemplate).where(
        PreTestTemplate.user_id == user_id,
        PreTestTemplate.deleted_at.is_(None),
    )

    if platform:
        query = query.where(PreTestTemplate.platform == platform)

    query = query.order_by(PreTestTemplate.is_default.desc(), PreTestTemplate.created_at.desc())

    total_result = await db.execute(query.with_only_columns(PreTestTemplate.id))
    total = len(total_result.scalars().all())

    offset = (page - 1) * page_size
    query = query.offset(offset).limit(page_size)

    result = await db.execute(query)
    templates = result.scalars().all()

    return {
        "data": templates,
        "total": total,
        "page": page,
        "page_size": page_size,
    }


async def get_default_template(
    user_id: str,
    db: AsyncSession,
) -> Optional[PreTestTemplate]:
    # 如果有默认模板，返回默认模板
    # 如果有多条默认的模板，返回最新创建的模板
    # 如果没有设置默认模板，返回最新创建的模板
    result = await db.execute(
        select(PreTestTemplate)
        .where(
            PreTestTemplate.user_id == user_id,
            PreTestTemplate.is_default == True,
            PreTestTemplate.deleted_at.is_(None),
        )
        .order_by(PreTestTemplate.created_at.desc())
    )
    template = result.scalar_one_or_none()

    if template:
        return template

    # 如果没有默认模板，返回最新创建的模板
    result = await db.execute(
        select(PreTestTemplate)
        .where(
            PreTestTemplate.user_id == user_id,
            PreTestTemplate.deleted_at.is_(None),
        )
        .order_by(PreTestTemplate.created_at.desc())
    )
    return result.scalar_one_or_none()