import json
from functools import cached_property

import psycopg
import psycopg.conninfo
from aws_lambda_powertools.utilities import parameters
from pydantic_settings import BaseSettings


class Settings(BaseSettings):
    stage: str | None = None
    service: str | None = None
    postgres_host: str | None = None
    postgres_port: int | None = None
    postgres_user: str | None = None
    postgres_password: str | None = None
    postgres_db: str | None = None
    postgres_secret_name: str | None = None
    s3_role_arn: str | None = None
    usage_event_consumer_function_name: str | None = None
    usage_event_storage_name: str | None = None
    usage_event_queue_url: str | None = None
    user_pool_jwks_endpoint_url: str | None = None
    management_m2m_pool_id: str | None = None
    management_user_pool_id: str | None = None
    management_console_domain: str | None = None
    application_log_level: str = "INFO"
    user_pool_id: str | None = None
    sns_topic_arn: str | None = None
    aws_region: str | None = None

    @cached_property
    def postgres_url(self) -> str:
        # クラウド環境ではシークレットから取得する
        if self.postgres_secret_name:
            one_year = 31104000
            # snapshot内のキャッシュを参照するため、十分な有効期限を設定する
            secret = json.loads(parameters.get_secret(self.postgres_secret_name, max_age=one_year))
            return psycopg.conninfo.make_conninfo(
                host=self.postgres_host,
                port=self.postgres_port,
                user=secret.get("username"),
                password=secret.get("password"),
                dbname=self.postgres_db,
                sslmode="disable",
            )

        return psycopg.conninfo.make_conninfo(
            host=self.postgres_host,
            port=self.postgres_port,
            user=self.postgres_user,
            password=self.postgres_password,
            dbname=self.postgres_db,
        )

    @property
    def management_m2m_issuer(self) -> str | None:
        """M2M用 User Pool ID から issuer URL を組み立てる"""
        if not self.management_m2m_pool_id:
            return None
        region = self.management_m2m_pool_id.split("_")[0]
        return f"https://cognito-idp.{region}.amazonaws.com/{self.management_m2m_pool_id}"

    @property
    def management_user_issuer(self) -> str | None:
        """エンドユーザー用 User Pool ID から issuer URL を組み立てる"""
        if not self.management_user_pool_id:
            return None
        if self.stage == "local":
            # floci が発行する JWT の iss クレームが http://localhost:4566 固定のため、それに合わせる
            return f"http://localhost:4566/{self.management_user_pool_id}"

        region = self.management_user_pool_id.split("_")[0]
        return f"https://cognito-idp.{region}.amazonaws.com/{self.management_user_pool_id}"

    @property
    def management_user_jwks_url(self) -> str | None:
        """エンドユーザー用 User Pool ID から JWKS URL を組み立てる"""
        if not self.management_user_pool_id:
            return None
        if self.stage == "local":
            # issuer は localhost だが、コンテナ間通信では localhost は自コンテナを指すため、
            # JWKS の取得先は Docker サービス名 (floci) を使う
            return f"http://floci:4566/{self.management_user_pool_id}/.well-known/jwks.json"

        # 本番ではissuerと同じベースURL
        return f"{self.management_user_issuer}/.well-known/jwks.json"
