import time
import os
import config
import email_send
from celery import shared_task
from app import db
from misc_utils import *
from models import *
from smtplib import SMTP


@shared_task(ignore_result=False)
def send_notification(notification_id, users, level):
    notification = db.session.get(Notification, notification_id)

    for user in users:
        db.session.add(UserNotification(db.session.get(User, user), notification, level))

        if db.session.get(User, user).email:
            with (SMTP(config.MAIL_SERVER) as mail):
                if notification.data.get("type") == "welcome":
                    message = email_send.make_multipart_message(
                            f"Welcome, {user}",
                            config.NOTIFICATION_EMAIL,
                            db.session.get(User, user).email,
                            "welcome",
                            username=user)

                mail.sendmail(config.NOTIFICATION_EMAIL, db.session.get(User, user).email, message)
    db.session.commit()

    return 0  # notification sent successfully


@shared_task(ignore_result=False)
def merge_heads(head_route, head_branch, base_route, base_branch, simulate=True):
    server_repo_location = os.path.join(config.REPOS_PATH, base_route.lstrip("/"))
    if not os.path.isdir(server_repo_location):
        raise FileNotFoundError(f"Repo {server_repo_location} not found, cannot merge.")

    if base_route == head_route:
        git_command(server_repo_location, b"", "checkout", f"{base_branch}")
        if simulate:
            out, err = git_command(server_repo_location, b"", "merge", "--no-commit", "--no-ff", f"heads/{head_branch}",
                                   return_err=True)

            # Undo the merge.
            git_command(server_repo_location, b"", "merge", "--abort")
        else:
            out, err = git_command(server_repo_location, b"", "merge", f"heads/{head_branch}",
                                   return_err=True)

        return "merge_simulator" if simulate else "merge", out, err, head_route, head_branch, base_route, base_branch

    remote_url = os.path.join(config.BASE_DOMAIN, "git", base_route.lstrip("/"))

    out, err = b"", b""
    part_out, part_err = git_command(server_repo_location, b"", "remote", "add", "NEW", remote_url, return_err=True)
    out += part_out
    err += part_err
    part_out, part_err = git_command(server_repo_location, b"", "remote", "update", return_err=True)
    out += part_out
    err += part_err
    part_out, part_err = git_command(server_repo_location, b"", "checkout", f"{base_branch}", return_err=True)
    out += part_out
    err += part_err
    if simulate:
        part_out, part_err = git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories",
                                         "--no-commit", "--no-ff", f"NEW/{head_branch}", return_err=True)
    else:
        part_out, part_err = git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories",
                                         f"NEW/{head_branch}", return_err=True)
    out += part_out
    err += part_err
    part_out, part_err = git_command(server_repo_location, b"", "remote", "rm", "NEW", return_err=True)
    out += part_out
    err += part_err
    if simulate:
        # Undo the merge.
        git_command(server_repo_location, b"", "merge", "--abort")

    return "merge_simulator" if simulate else "merge", out, err, head_route, head_branch, base_route, base_branch
