from uuid import UUID

import psycopg
from aws_lambda_powertools.utilities.typing import LambdaContext
from src.infrastructure.database.execute_tenant_rls import execute_tenant_rls
from src.infrastructure.repositories.tenant_repository import TenantRepository
from src.infrastructure.repositories.user_repository import UserRepository
from src.logger import logger
from src.settings import Settings

settings = Settings()

# Cognito CustomMessage トリガーソース定数
_TRIGGER_FORGOT_PASSWORD = "CustomMessage_ForgotPassword"  # noqa: S105
_TRIGGER_ADMIN_CREATE_USER = "CustomMessage_AdminCreateUser"


def handler(event: dict, _: LambdaContext) -> dict:
    trigger_source = event.get("triggerSource")

    # 対応外のトリガーソースは早期リターン
    if trigger_source not in (_TRIGGER_FORGOT_PASSWORD, _TRIGGER_ADMIN_CREATE_USER):
        return event

    request = event.get("request", {})
    user_attributes = request.get("userAttributes", {})
    try:
        tenant_id = UUID(user_attributes["custom:tenant_id"])
        user_id = UUID(user_attributes["custom:user_id"])
    except (KeyError, ValueError):
        logger.exception("Invalid custom attributes.", user_attributes=user_attributes)
        raise

    with psycopg.connect(settings.postgres_url) as connection:
        execute_tenant_rls(connection=connection, tenant_id=tenant_id)
        tenant = TenantRepository(connection=connection).get(tenant_id=tenant_id)
        user = UserRepository(tenant=tenant, connection=connection).get(user_id=user_id)

    # メール送信を失敗させるため、テンプレートに必要な情報が不足している場合は例外を発生させる
    if not tenant.name or not settings.management_console_domain:
        logger.error("Missing tenant name or management console domain for email template.", tenant_id=tenant_id)
        raise ValueError("Missing tenant name or management console domain")

    if trigger_source == _TRIGGER_FORGOT_PASSWORD:
        subject = _RESET_PASSWORD_SUBJECT
        body = _RESET_PASSWORD_BODY_TEMPLATE.format(
            console_domain=settings.management_console_domain,
            code=request.get("codeParameter", ""),
            tenant_name=tenant.name,
        )
    else:
        subject = _INVITATION_SUBJECT
        body = _INVITATION_BODY_TEMPLATE.format(
            display_id=user.display_id,
            console_domain=settings.management_console_domain,
            tenant_name=tenant.name,
        )

    event.setdefault("response", {})
    event["response"]["emailSubject"] = subject
    event["response"]["emailMessage"] = body

    return event


# ---------------------------------------------------------------------------
# メールテンプレート定数
#
# 定数を上部に配置するとコードの可読性が下がるため下部にまとめている。
# Cognito が {####} を一時パスワード/検証コードに置換するため、
# str.format() のエスケープとして {{####}} を使用している。
# 新規追加時の招待メールには username が必須のため、コメントアウトで残している。
# ---------------------------------------------------------------------------

_INVITATION_SUBJECT = (
    "COMPANY AIユニット管理画面 アカウント追加のお知らせ / Invite to join COMPANY AI Unit Management Console"
)

_INVITATION_BODY_TEMPLATE = """\
* Followed by English translation.<br>
<br>
COMPANY AIユニット管理画面をご利用いただき、ありがとうございます。<br>
<br>
お客様のアカウントの追加処理が完了しました。<br>
下記ログインURLより、ユーザーIDと一時パスワードを入力してログインをお願いいたします。<br>
※初回ログイン時のみパスワード変更画面が表示されますので、任意の新パスワードへ変更してください。<br>
<br>
■ ログインURL<br>
https://{tenant_name}.{console_domain}<br>
■ 登録ユーザーID<br>
{display_id}<br>
■ 一時パスワード<br>
{{####}}<br>
<br>
※本メールの受信後7日以内にログインされない場合、一時パスワードが無効となります。<br>
万が一、パスワードが無効になってしまった際は、システム管理者にアカウントの再作成を依頼してください。<br>
<br>
---------------------------------------------------------------------------------<br>
Thank you for using COMPANY AI Management Console.<br>
<br>
Your account setup has been completed.<br>
Please log in to the application using the URL below with your User ID and temporary password.<br>
*Upon your initial login, you will be directed to a password change screen. Please choose and set your own new password.<br>
<br>
■ Login URL<br>
https://{tenant_name}.{console_domain}<br>
■ User ID<br>
{display_id}<br>
■ Temporary Password<br>
{{####}}<br>
<br>
*Please note that the temporary password will expire if you do not log in within 7 days of receiving this email.<br>
If the password expires, please request your system administrator to re-create your account.

<!-- {{username}} -->
"""  # noqa: E501

_RESET_PASSWORD_SUBJECT = (
    "COMPANY AIユニット管理画面パスワード再設定手続きのお知らせ"  # noqa: S105
    " / Password reset request for COMPANY AI Unit Management Console"
)

_RESET_PASSWORD_BODY_TEMPLATE = """\
* Followed by English translation.<br>
<br>
COMPANY AIユニット管理画面をご利用いただき、ありがとうございます。<br>
<br>
お客様のアカウントのパスワード再設定手続きのためのURLをお送りします。<br>
下記のURLにアクセスし、パスワードの変更を完了させてください。<br>
<br>
■ パスワード再設定URL<br>
https://{tenant_name}.{console_domain}/reset-password?code={code}<br>
<br>
※本メールに心当たりがない場合は、このままメールを破棄してください。<br>
<br>
--------------------------------------------------<br>
Thank you for using COMPANY AI Unit Management Console.<br>
<br>
We have received a request to reset the password for your account.<br>
Please click the URL below to set a new password.<br>
<br>
■ Password Reset URL<br>
https://{tenant_name}.{console_domain}/reset-password?code={code}<br>
<br>
*If you did not request this, please disregard this email.
"""  # noqa: S105
