"""Shopify App domain - data access."""
from __future__ import annotations

from typing import Optional
from uuid import UUID

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

from src.domain.shopify_apps.models import ShopifyAppConfig, ShopifyAppFunction, ShopifyAppResources


class ShopifyAppConfigRepository:
    def __init__(self, session: AsyncSession) -> None:
        self.session = session

    async def get(self, project_id: UUID) -> Optional[ShopifyAppConfig]:
        result = await self.session.execute(
            select(ShopifyAppConfig).where(ShopifyAppConfig.project_id == project_id)
        )
        return result.scalar_one_or_none()

    async def upsert(self, project_id: UUID, **kwargs) -> ShopifyAppConfig:
        row = await self.get(project_id)
        if row is None:
            row = ShopifyAppConfig(project_id=project_id)
            self.session.add(row)
        for k, v in kwargs.items():
            if hasattr(row, k):
                setattr(row, k, v)
        await self.session.flush()
        return row


class ShopifyAppFunctionRepository:
    def __init__(self, session: AsyncSession) -> None:
        self.session = session

    async def get_by_id(self, function_id: UUID, project_id: UUID) -> Optional[ShopifyAppFunction]:
        result = await self.session.execute(
            select(ShopifyAppFunction).where(
                ShopifyAppFunction.id == function_id,
                ShopifyAppFunction.project_id == project_id,
            )
        )
        return result.scalar_one_or_none()

    async def get_by_slug(self, project_id: UUID, slug: str) -> Optional[ShopifyAppFunction]:
        result = await self.session.execute(
            select(ShopifyAppFunction).where(
                ShopifyAppFunction.project_id == project_id,
                ShopifyAppFunction.slug == slug,
            )
        )
        return result.scalar_one_or_none()

    async def list_for_project(self, project_id: UUID) -> list[ShopifyAppFunction]:
        result = await self.session.execute(
            select(ShopifyAppFunction)
            .where(ShopifyAppFunction.project_id == project_id)
            .order_by(ShopifyAppFunction.created_at)
        )
        return list(result.scalars().all())

    async def create(
        self,
        project_id: UUID,
        name: str,
        slug: str,
        trigger_type: str,
        *,
        description: Optional[str] = None,
        cron_schedule: Optional[str] = None,
        webhook_topic: Optional[str] = None,
        code_ts: Optional[str] = None,
    ) -> ShopifyAppFunction:
        fn = ShopifyAppFunction(
            project_id=project_id,
            name=name,
            slug=slug,
            trigger_type=trigger_type,
            description=description,
            cron_schedule=cron_schedule,
            webhook_topic=webhook_topic,
            code_ts=code_ts,
        )
        self.session.add(fn)
        await self.session.flush()
        return fn

    async def update(self, fn: ShopifyAppFunction, **kwargs) -> ShopifyAppFunction:
        for k, v in kwargs.items():
            if hasattr(fn, k):
                setattr(fn, k, v)
        await self.session.flush()
        return fn

    async def delete(self, fn: ShopifyAppFunction) -> None:
        await self.session.delete(fn)
        await self.session.flush()


class ShopifyAppResourcesRepository:
    def __init__(self, session: AsyncSession) -> None:
        self.session = session

    async def get(self, project_id: UUID) -> Optional[ShopifyAppResources]:
        result = await self.session.execute(
            select(ShopifyAppResources).where(ShopifyAppResources.project_id == project_id)
        )
        return result.scalar_one_or_none()

    async def upsert(self, project_id: UUID, **kwargs) -> ShopifyAppResources:
        row = await self.get(project_id)
        if row is None:
            row = ShopifyAppResources(project_id=project_id)
            self.session.add(row)
        for k, v in kwargs.items():
            if hasattr(row, k):
                setattr(row, k, v)
        await self.session.flush()
        return row
