from datetime import datetime, timedelta, timezone
from functools import lru_cache
import json
from pathlib import Path
import secrets
from threading import Lock

from app.core.config import get_settings
from app.models.google_workspace import (
    GoogleWorkspaceConnection,
    GoogleWorkspacePendingAuthorization,
    GoogleWorkspaceState,
)


def utc_now() -> datetime:
    return datetime.now(timezone.utc)


def utc_now_isoformat() -> str:
    return utc_now().isoformat()


class GoogleWorkspaceStore:
    def __init__(self, state_file: str) -> None:
        self._path = Path(state_file)
        self._lock = Lock()

    def _ensure_parent(self) -> None:
        self._path.parent.mkdir(parents=True, exist_ok=True)

    def _read_state(self) -> GoogleWorkspaceState:
        if not self._path.exists():
            return GoogleWorkspaceState()

        payload = json.loads(self._path.read_text(encoding="utf-8"))
        return GoogleWorkspaceState.model_validate(payload)

    def _write_state(self, state: GoogleWorkspaceState) -> None:
        self._ensure_parent()
        self._path.write_text(state.model_dump_json(indent=2), encoding="utf-8")

    def _prune_pending(self, state: GoogleWorkspaceState) -> GoogleWorkspaceState:
        threshold = utc_now() - timedelta(minutes=15)
        state.pending_authorizations = [
            item
            for item in state.pending_authorizations
            if datetime.fromisoformat(item.created_at) >= threshold
        ]
        return state

    def get_connection(self, tenant_id: str, *, adopt_legacy_if_needed: bool = False) -> GoogleWorkspaceConnection | None:
        with self._lock:
            state = self._prune_pending(self._read_state())
            connection = state.tenant_connections.get(tenant_id)
            if connection is None and adopt_legacy_if_needed and state.legacy_connection is not None and not state.tenant_connections:
                state.tenant_connections[tenant_id] = state.legacy_connection
                state.legacy_connection = None
                connection = state.tenant_connections.get(tenant_id)
            self._write_state(state)
            return connection

    def set_connection(self, tenant_id: str, connection: GoogleWorkspaceConnection) -> None:
        with self._lock:
            state = self._prune_pending(self._read_state())
            state.tenant_connections[tenant_id] = connection
            self._write_state(state)

    def clear_connection(self, tenant_id: str) -> None:
        with self._lock:
            state = self._prune_pending(self._read_state())
            state.tenant_connections.pop(tenant_id, None)
            self._write_state(state)

    def list_connected_tenant_ids(self) -> list[str]:
        with self._lock:
            state = self._prune_pending(self._read_state())
            self._write_state(state)
            return sorted(state.tenant_connections.keys())

    def create_pending_authorization(self, tenant_id: str, return_to: str) -> GoogleWorkspacePendingAuthorization:
        with self._lock:
            state = self._prune_pending(self._read_state())
            pending = GoogleWorkspacePendingAuthorization(
                state=secrets.token_urlsafe(32),
                code_verifier=secrets.token_urlsafe(72),
                tenant_id=tenant_id,
                return_to=return_to,
                created_at=utc_now_isoformat(),
            )
            state.pending_authorizations.append(pending)
            self._write_state(state)
            return pending

    def consume_pending_authorization(self, state_token: str) -> GoogleWorkspacePendingAuthorization | None:
        with self._lock:
            state = self._prune_pending(self._read_state())
            match: GoogleWorkspacePendingAuthorization | None = None
            remaining: list[GoogleWorkspacePendingAuthorization] = []

            for item in state.pending_authorizations:
                if item.state == state_token and match is None:
                    match = item
                    continue
                remaining.append(item)

            state.pending_authorizations = remaining
            self._write_state(state)
            return match


@lru_cache
def get_google_workspace_store() -> GoogleWorkspaceStore:
    settings = get_settings()
    return GoogleWorkspaceStore(settings.google_workspace_state_file)
