import base64
import logging
import re

import orjson
from flask import current_app, make_response, render_template, request, session

from src.config import Configuration
from src.internals.cache.redis import get_conn
from src.internals.database.database import query_db, query_one_db
from src.lib.imports import validate_import_key
from src.pages.api.v1 import v1api_bp
from src.types.props import SuccessProps


@v1api_bp.post("/importer/submit")
def importer_submit():
    if not session.get("account_id") and request.form.get("save_dms") and request.form.get("service") == "patreon":
        return "You must be logged in to import direct messages.", 401

    if not request.form.get("session_key"):
        return "Session key missing.", 401

    key = request.form.get("session_key").strip().strip("\" \t'")
    if request.form.get("service") == "onlyfans":
        key = base64.b64encode(
            orjson.dumps(
                {
                    "sess": key,
                    "x-bc": request.form.get("x-bc").strip().strip("\" \t'"),
                    "auth_id": request.form.get("auth_id").strip().strip("\" \t'"),
                    "auth_uid_": "None",
                    "user_agent": request.form.get("user_agent").strip().strip("\" \t'"),
                }
            )
        ).decode()
    result = validate_import_key(key, request.form.get("service"))

    discord_channels = None
    if (input_channels := request.form.get("channel_ids")) and request.form.get("service") == "discord":
        regex = r"https://discord\.com/channels/\d+/(?P<ch>\d+)"
        input_channels = [
            re.match(regex, item).group("ch") if re.match(regex, item) else item for item in input_channels.split(",")
        ]
        discord_channels = list(s.strip() for s in re.split(r"[\s,.、。/']", ",".join(input_channels)) if s.strip())
        if any(not s.isdigit() for s in discord_channels):
            msg = "Discord channel ids are numbers, the last number of the url (notice the / between the 2 numbers)"
            logging.exception(msg, extra=dict(input_channels=input_channels, discord_channels=discord_channels))
            return msg, 422
        if not discord_channels:
            msg = "Discord submit requires channels"
            logging.exception(msg, extra=dict(input_channels=input_channels, discord_channels=discord_channels))
            return msg, 422
        discord_channels = ",".join(discord_channels)

    if not result.is_valid:
        return "\n".join(result.errors), 422

    formatted_key = result.modified_result if result.modified_result else key
    service = request.form.get("service")
    queue_name = f"import:{service}"

    existing_imports = query_db(
        b"""
        SELECT job_id
        FROM jobs
        WHERE finished_at IS null
        AND queue_name = %s
        AND job_input ->> 'key' = %s
        """,
        (queue_name, formatted_key)
    )

    if existing_imports:
        existing_import = existing_imports[0]["job_id"]
        props = SuccessProps(
            message="This key is already being used for an import. Redirecting to logs...",
            currentPage="import",
            redirect=f"/importer/status/{existing_import}{"?dms=1" if request.form.get("save_dms") else ""}",
        )

        return make_response(render_template("success.html", props=props), 200)

    data = dict(
        key=formatted_key,
        service=service,
        channel_ids=discord_channels,
        auto_import=request.form.get("auto_import"),
        save_session_key=request.form.get("save_session_key"),
        save_dms=request.form.get("save_dms"),
        contributor_id=session.get("account_id"),
        priority=1,
        country=request.headers.get(Configuration().webserver["country_header_key"]),
        user_agent=request.headers.get("User-Agent"),
    )
    query = b"""
        INSERT INTO jobs (queue_name, priority, job_input)
        VALUES (%s, %s, %s)
        RETURNING job_id;
    """
    import_id = query_one_db(query, (queue_name, 1, orjson.dumps(data).decode()))["job_id"]

    props = SuccessProps(
        currentPage="import",
        redirect=f"/importer/status/{import_id}{"?dms=1" if request.form.get("save_dms") else ""}",
    )

    return make_response(render_template("success.html", props=props), 200)


@v1api_bp.route("/importer/logs/<import_id>")
def get_importer_logs(import_id: str):
    redis = get_conn()
    key = f"importer_logs:{import_id}"
    llen = redis.llen(key)
    messages = []
    if llen > 0:
        messages = redis.lrange(key, 0, llen)
        redis.expire(key, 60 * 60 * 48)

    return orjson.dumps([msg.decode() for msg in messages]), 200
