import arrow
from flask import jsonify, g, request

from app.api.base import api_bp, require_api_auth
from app.db import Session
from app.log import LOG
from app.models import (
    User,
    AliasGeneratorEnum,
    SLDomain,
    CustomDomain,
    SenderFormatEnum,
    AliasSuffixEnum,
)
from app.proton.proton_unlink import perform_proton_account_unlink


def setting_to_dict(user: User):
    ret = {
        "notification": user.notification,
        "alias_generator": "word"
        if user.alias_generator == AliasGeneratorEnum.word.value
        else "uuid",
        "random_alias_default_domain": user.default_random_alias_domain(),
        # return the default sender format (AT) in case user uses a non-supported sender format
        "sender_format": SenderFormatEnum.get_name(user.sender_format)
        or SenderFormatEnum.AT.name,
        "random_alias_suffix": AliasSuffixEnum.get_name(user.random_alias_suffix),
    }

    return ret


@api_bp.route("/setting")
@require_api_auth
def get_setting():
    """
    Return user setting
    """
    user = g.user

    return jsonify(setting_to_dict(user))


@api_bp.route("/setting", methods=["PATCH"])
@require_api_auth
def update_setting():
    """
    Update user setting
    Input:
    - notification: bool
    - alias_generator: word|uuid
    - random_alias_default_domain: str
    """
    user = g.user
    data = request.get_json() or {}

    if "notification" in data:
        user.notification = data["notification"]

    if "alias_generator" in data:
        alias_generator = data["alias_generator"]
        if alias_generator not in ["word", "uuid"]:
            return jsonify(error="Invalid alias_generator"), 400

        if alias_generator == "word":
            user.alias_generator = AliasGeneratorEnum.word.value
        else:
            user.alias_generator = AliasGeneratorEnum.uuid.value

    if "sender_format" in data:
        sender_format = data["sender_format"]
        if not SenderFormatEnum.has_name(sender_format):
            return jsonify(error="Invalid sender_format"), 400

        user.sender_format = SenderFormatEnum.get_value(sender_format)
        user.sender_format_updated_at = arrow.now()

    if "random_alias_suffix" in data:
        random_alias_suffix = data["random_alias_suffix"]
        if not AliasSuffixEnum.has_name(random_alias_suffix):
            return jsonify(error="Invalid random_alias_suffix"), 400

        user.random_alias_suffix = AliasSuffixEnum.get_value(random_alias_suffix)

    if "random_alias_default_domain" in data:
        default_domain = data["random_alias_default_domain"]
        sl_domain: SLDomain = SLDomain.get_by(domain=default_domain)
        if sl_domain:
            if sl_domain.premium_only and not user.is_premium():
                return jsonify(error="You cannot use this domain"), 400

            user.default_alias_public_domain_id = sl_domain.id
            user.default_alias_custom_domain_id = None
        else:
            custom_domain = CustomDomain.get_by(domain=default_domain)
            if not custom_domain:
                return jsonify(error="invalid domain"), 400

            # sanity check
            if custom_domain.user_id != user.id or not custom_domain.verified:
                LOG.w("%s cannot use domain %s", user, default_domain)
                return jsonify(error="invalid domain"), 400
            else:
                user.default_alias_custom_domain_id = custom_domain.id
                user.default_alias_public_domain_id = None

    Session.commit()
    return jsonify(setting_to_dict(user))


@api_bp.route("/setting/domains")
@require_api_auth
def get_available_domains_for_random_alias():
    """
    Available domains for random alias
    """
    user = g.user

    ret = [
        (is_sl, domain) for is_sl, domain in user.available_domains_for_random_alias()
    ]

    return jsonify(ret)


@api_bp.route("/v2/setting/domains")
@require_api_auth
def get_available_domains_for_random_alias_v2():
    """
    Available domains for random alias
    """
    user = g.user

    ret = [
        {"domain": domain, "is_custom": not is_sl}
        for is_sl, domain in user.available_domains_for_random_alias()
    ]

    return jsonify(ret)


@api_bp.route("/setting/unlink_proton_account", methods=["DELETE"])
@require_api_auth
def unlink_proton_account():
    user = g.user
    if not perform_proton_account_unlink(user):
        return jsonify(error="The account cannot be unlinked"), 400
    return jsonify({"ok": True})
