from __future__ import annotations

import json
from datetime import datetime
from typing import Any, Dict, List, Optional

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

from fmatch.saas.model_defs.salesforce_ai_reports import SalesforceAIReport


class SalesforceAIReportsRepo:
    """Persistence helpers for AI-generated SOQL report artifacts."""

    def __init__(self, db: AsyncSession) -> None:
        self.db = db

    @staticmethod
    def _json_dump(value: Any) -> str:
        try:
            return json.dumps(value or {}, separators=(",", ":"), ensure_ascii=False)
        except Exception:
            return "{}"

    async def create_report(
        self,
        *,
        account_id: str,
        user_id: str,
        name: str,
        description: Optional[str],
        primary_object: str,
        plan_json: Dict[str, Any],
        compiled_soql: str,
        plan_hash: str,
        tier: Optional[str],
        scopes: Optional[List[str]] = None,
        schedule: Optional[Dict[str, Any]] = None,
    ) -> SalesforceAIReport:
        row = SalesforceAIReport(
            account_id=str(account_id),
            user_id=str(user_id),
            name=name.strip(),
            description=description.strip() if description else None,
            primary_object=primary_object,
            plan_json=json.dumps(plan_json, ensure_ascii=False, separators=(",", ":")),
            compiled_soql=compiled_soql,
            plan_hash=plan_hash,
            tier=tier,
            scopes_json=json.dumps(scopes or [], ensure_ascii=False),
            schedule_json=self._json_dump(schedule),
            created_at=datetime.utcnow(),
            updated_at=datetime.utcnow(),
        )
        self.db.add(row)
        await self.db.commit()
        await self.db.refresh(row)
        return row

    async def list_reports(
        self,
        *,
        account_id: str,
        include_archived: bool = False,
        limit: int = 50,
    ) -> List[SalesforceAIReport]:
        stmt = (
            select(SalesforceAIReport)
            .where(SalesforceAIReport.account_id == str(account_id))
            .order_by(SalesforceAIReport.created_at.desc())
            .limit(limit)
        )
        if not include_archived:
            stmt = stmt.where(SalesforceAIReport.archived_at.is_(None))
        rows = (await self.db.execute(stmt)).scalars().all()
        return list(rows)

    async def get_report(
        self, report_id: str, *, account_id: str
    ) -> Optional[SalesforceAIReport]:
        row = await self.db.get(SalesforceAIReport, report_id)
        if not row:
            return None
        if row.account_id != str(account_id):
            return None
        return row

    async def archive_report(self, report_id: str, *, account_id: str) -> bool:
        row = await self.get_report(report_id, account_id=account_id)
        if not row:
            return False
        row.archived_at = datetime.utcnow()
        row.updated_at = datetime.utcnow()
        await self.db.commit()
        return True

    async def update_last_run(
        self,
        report_id: str,
        *,
        account_id: str,
        result_payload: Dict[str, Any],
    ) -> bool:
        row = await self.get_report(report_id, account_id=account_id)
        if not row:
            return False
        row.last_run_json = json.dumps(
            result_payload or {}, ensure_ascii=False, separators=(",", ":")
        )
        row.updated_at = datetime.utcnow()
        await self.db.commit()
        return True
