import logging
import json
from jsonschema import validate
from jsonschema.exceptions import ValidationError
from app.classes.models.users import Users
from app.classes.shared.helpers import Helpers
from app.classes.web.base_api_handler import BaseApiHandler

logger = logging.getLogger(__name__)

login_schema = {
    "type": "object",
    "properties": {
        "username": {
            "type": "string",
            "maxLength": 20,
            "minLength": 4,
            "pattern": "^[a-z0-9_]+$",
        },
        "password": {"type": "string", "maxLength": 20, "minLength": 4},
    },
    "required": ["username", "password"],
    "additionalProperties": False,
}


class ApiAuthLoginHandler(BaseApiHandler):
    def post(self):

        try:
            data = json.loads(self.request.body)
        except json.decoder.JSONDecodeError as e:
            return self.finish_json(
                400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
            )

        try:
            validate(data, login_schema)
        except ValidationError as e:
            return self.finish_json(
                400,
                {
                    "status": "error",
                    "error": "INVALID_JSON_SCHEMA",
                    "error_data": str(e),
                },
            )

        username = data["username"]
        password = data["password"]

        # pylint: disable=no-member
        user_data = Users.get_or_none(Users.username == username)

        if user_data is None:
            return self.finish_json(
                401,
                {"status": "error", "error": "INCORRECT_CREDENTIALS", "token": None},
            )

        if not user_data.enabled:
            self.finish_json(
                403, {"status": "error", "error": "ACCOUNT_DISABLED", "token": None}
            )
            return

        login_result = self.helper.verify_pass(password, user_data.password)

        # Valid Login
        if login_result:
            logger.info(f"User: {user_data} Logged in from IP: {self.get_remote_ip()}")

            # record this login
            query = Users.select().where(Users.username == username.lower()).get()
            query.last_ip = self.get_remote_ip()
            query.last_login = Helpers.get_time_as_string()
            query.save()

            # log this login
            self.controller.management.add_to_audit_log(
                user_data.user_id, "logged in via the API", 0, self.get_remote_ip()
            )

            self.finish_json(
                200,
                {
                    "status": "ok",
                    "data": {
                        "token": self.controller.authentication.generate(
                            user_data.user_id
                        ),
                        "user_id": str(user_data.user_id),
                    },
                },
            )
        else:
            # log this failed login attempt
            self.controller.management.add_to_audit_log(
                user_data.user_id, "Tried to log in", 0, self.get_remote_ip()
            )
            self.finish_json(
                401,
                {"status": "error", "error": "INCORRECT_CREDENTIALS"},
            )
