import uuid

from app import app, gitCommand, User, Repo, Commit, RepoAccess, getPermissionLevel, getVisibility, db, bcrypt
import os
import shutil
import config
import flask
import git
import subprocess
from flask_httpauth import HTTPBasicAuth
import zlib
import re
import datetime

auth = HTTPBasicAuth(realm=config.AUTH_REALM)


authRequired = flask.Response("Unauthorized Access", 401, {"WWW-Authenticate": 'Basic realm="Login Required"'})


@auth.verify_password
def verifyPassword(username, password):
    user = User.query.filter_by(username=username).first()

    if user and bcrypt.check_password_hash(user.passwordHashed, password):
        flask.g.user = username
        return True

    return False


@app.route("/git/<username>/<repository>/git-upload-pack", methods=["POST"])
@auth.login_required(optional=True)
def gitUploadPack(username, repository):
    if auth.current_user() is None and not getVisibility(username, repository):
        return authRequired
    if not (getVisibility(username, repository) or getPermissionLevel(flask.g.user, username, repository) is not None):
        flask.abort(403)

    serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git")
    text = gitCommand(serverRepoLocation, flask.request.data, "upload-pack", "--stateless-rpc", ".")

    return flask.Response(text, content_type="application/x-git-upload-pack-result")


@app.route("/git/<username>/<repository>/git-receive-pack", methods=["POST"])
@auth.login_required
def gitReceivePack(username, repository):
    if not getPermissionLevel(flask.g.user, username, repository):
        flask.abort(403)

    serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git")
    text = gitCommand(serverRepoLocation, flask.request.data, "receive-pack", "--stateless-rpc", ".")

    sha = flask.request.data.split(b" ", 2)[1].decode()
    info = gitCommand(serverRepoLocation, None, "show", "-s", "--format='%H%n%at%n%cn <%ce>%n%B'", sha).decode()

    if re.match("^[0-9a-fA-F]{40}$", info[:40]):
        print(info.split("\n", 3))
        sha, time, identity, body = info.split("\n", 3)
        login = flask.g.user

        user = User.query.filter_by(username=login).first()
        repo = Repo.query.filter_by(route=f"/{username}/{repository}").first()
        commit = Commit(sha, user, repo, time, body, identity)

        db.session.add(commit)
        db.session.commit()

    return flask.Response(text, content_type="application/x-git-receive-pack-result")


@app.route("/git/<username>/<repository>/info/refs", methods=["GET"])
@auth.login_required(optional=True)
def gitInfoRefs(username, repository):
    serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository, ".git")

    repo = git.Repo(serverRepoLocation)
    repoData = Repo.query.filter_by(route=f"/{username}/{repository}").first()
    if not repoData.defaultBranch:
        if repo.heads:
            repoData.defaultBranch = repo.heads[0].name
            repo.git.checkout("-f", repoData.defaultBranch)

    if auth.current_user() is None and (not getVisibility(username, repository) or flask.request.args.get("service") == "git-receive-pack"):
        return authRequired
    try:
        if not (getVisibility(username, repository) or getPermissionLevel(flask.g.user, username, repository) is not None):
            flask.abort(403)
    except AttributeError:
        return authRequired

    service = flask.request.args.get("service")

    if service.startswith("git"):
        service = service[4:]
    else:
        flask.abort(403)

    if service == "receive-pack":
        try:
            if not getPermissionLevel(flask.g.user, username, repository):
                flask.abort(403)
        except AttributeError:
            return authRequired

    serviceLine = f"# service=git-{service}\n"
    serviceLine = (f"{len(serviceLine) + 4:04x}" + serviceLine).encode()

    if service == "upload-pack":
        text = serviceLine + b"0000" + gitCommand(serverRepoLocation, None, "upload-pack", "--stateless-rpc", "--advertise-refs", "--http-backend-info-refs", ".")
    elif service == "receive-pack":
        refs = gitCommand(serverRepoLocation, None, "receive-pack", "--http-backend-info-refs", ".")
        text = serviceLine + b"0000" + refs
    else:
        flask.abort(403)

    response = flask.Response(text, content_type=f"application/x-git-{service}-advertisement")
    response.headers["Cache-Control"] = "no-cache"

    return response

