from __future__ import annotations

import os
import re
from dataclasses import dataclass, field

EXPECTED_PROJECT = "teleo-501523"
EXPECTED_REGION = "europe-west6"
EXPECTED_INSTANCE = "teleo-pgvector-standby"
EXPECTED_CONNECTION_NAME = f"{EXPECTED_PROJECT}:{EXPECTED_REGION}:{EXPECTED_INSTANCE}"
EXPECTED_DATABASE = "teleo_canonical"
EXPECTED_AUTHORIZATION_ROLE = "kb_observatory_read"
EXPECTED_IAM_DATABASE_USER = f"sa-observatory-read-adapter@{EXPECTED_PROJECT}.iam"
SERVICE_REVISION_PATTERN = re.compile(r"^[0-9a-f]{40}$")


@dataclass(frozen=True)
class Settings:
    project_id: str
    instance_connection_name: str
    database: str
    iam_database_user: str
    authorization_role: str
    api_key: str = field(repr=False)
    service_revision: str = "unknown"
    port: int = 8080

    @classmethod
    def from_env(cls) -> Settings:
        settings = cls(
            project_id=os.environ.get("GCP_PROJECT_ID", ""),
            instance_connection_name=os.environ.get("CLOUD_SQL_INSTANCE", ""),
            database=os.environ.get("DB_NAME", ""),
            iam_database_user=os.environ.get("DB_IAM_USER", ""),
            authorization_role=os.environ.get("DB_AUTHORIZATION_ROLE", ""),
            api_key=os.environ.get("OBSERVATORY_API_KEY", ""),
            service_revision=os.environ.get("SERVICE_REVISION", "unknown"),
            port=int(os.environ.get("PORT", "8080")),
        )
        settings.validate()
        return settings

    def validate(self) -> None:
        if self.project_id != EXPECTED_PROJECT:
            raise ValueError(f"GCP_PROJECT_ID must be {EXPECTED_PROJECT}")
        if self.instance_connection_name != EXPECTED_CONNECTION_NAME:
            raise ValueError(f"CLOUD_SQL_INSTANCE must be {EXPECTED_CONNECTION_NAME}")
        if self.database != EXPECTED_DATABASE:
            raise ValueError(f"DB_NAME must be {EXPECTED_DATABASE}")
        if self.authorization_role != EXPECTED_AUTHORIZATION_ROLE:
            raise ValueError(f"DB_AUTHORIZATION_ROLE must be {EXPECTED_AUTHORIZATION_ROLE}")
        if self.iam_database_user != EXPECTED_IAM_DATABASE_USER:
            raise ValueError(f"DB_IAM_USER must be {EXPECTED_IAM_DATABASE_USER}")
        if (
            len(self.api_key) < 32
            or len(self.api_key) > 512
            or not self.api_key.isascii()
            or any(character.isspace() for character in self.api_key)
        ):
            raise ValueError("OBSERVATORY_API_KEY must be 32-512 non-whitespace ASCII characters")
        if SERVICE_REVISION_PATTERN.fullmatch(self.service_revision) is None:
            raise ValueError("SERVICE_REVISION must be a lowercase 40-character Git commit SHA")
        if not 1 <= self.port <= 65535:
            raise ValueError("PORT is outside the valid TCP port range")
