import os
from flask import request, logging, send_file, jsonify
from app import app
from .resp import success_resp, error_resp
import numpy as np
from .req import ReplaceForm, is_empty
import tools
import cv2
from .file import get_upload_file_path, get_output_dir, file_url, get_output_file_path, get_file_id, get_file_id_path
from utils import color
import time

log = logging.create_logger(app)


@app.route("/image/seg", methods=['POST'])
def seg():
    if 'fileId' not in request.values:
        return "请先上传图片！", 500
    file_id = request.values.get('fileId')

    file_path = get_upload_file_path(file_id)
    _, fg, _, path = tools.seg(file_path, get_output_dir())
    # filename = os.path.relpath(path, OUTPUT_DIR)
    return jsonify(success_resp({
        "fileId": file_id,
        "url": file_url(path, True)
    }))


@app.route("/image/replace", methods=["POST"])
def replace():
    form_data = request.form
    form = ReplaceForm(form_data)
    if form.validate() is False:
        return jsonify(error_resp("参数错误！"))

    img_path = get_file_id_path(form.file_id.data)

    exist, alpha_path, path = tools.has_seg(img_path, get_output_dir())

    if exist:
        alpha = cv2.imread(alpha_path)
        fg = cv2.imread(path)
    else:
        alpha, fg, _, path = tools.seg(img_path, get_output_dir())

    if is_empty(form.bg_file_id.data) and is_empty(form.background.data):
        return jsonify(success_resp({
            "fileId": form.file_id.data,
            "url": file_url(path, True)
        }))

    bg_path = form.background.data

    if is_empty(form.bg_file_id.data) is False:
        bg_path = get_upload_file_path(form.bg_file_id.data)
        if os.path.exists(bg_path) is False:
            bg_path = form.background.data

    bg = color.get_bg(bg_path, fg.shape)
    if bg is None:
        return jsonify(success_resp({
            "fileId": form.file_id.data,
            "url": file_url(path, True)
        }))

    alpha = alpha / 255.0
    alpha = alpha[:, :, np.newaxis]
    com = alpha * fg + (1 - alpha) * bg
    com = com.astype('uint8')
    filename = os.path.basename(img_path)
    names = os.path.splitext(filename)
    save_name = "{}_{}{}".format(names[0], time.time(), names[1])
    com_save_path = os.path.join(get_output_dir(), save_name)
    cv2.imwrite(com_save_path, com)

    return jsonify(success_resp({
        "fileId": get_file_id(com_save_path, True),
        "url": file_url(com_save_path, True)
    }))


@app.route("/image/resize", methods=["POST", 'GET'])
def resize():
    # flip: 翻转， 0 为沿X轴翻转，正数为沿Y轴翻转，负数为同时沿X轴和Y轴翻转
    # reset: 是否重头开始，否则从上一次的处理开始,默认为重头开始
    # resize: 重新设定尺寸
    # rect: 裁剪，left,top,right,bottom 四个参数
    reset = request.values.get("reset")
    file_id = request.values.get("fileId")
    width = request.values.get("width")
    height = request.values.get("height")
    rotate = request.values.get("rotate")
    flip = request.values.get("flip")
    rect = request.values.get('rect')
    save = request.values.get('onSave')
    download = request.values.get('download')
    save = is_empty(save) is False
    download = is_empty(download) is False

    if is_empty(reset):
        reset = True
    else:
        reset = False

    file_path = get_file_id_path(file_id)

    is_get = request.method.upper() == "GET"

    if os.path.exists(file_path) is not True:
        return "文件上传失败，请重新上传！" if is_get else jsonify(error_resp("文件上传失败，请重新上传")), 400

    out_file = get_output_file_path(file_id, "resize")
    if reset is False and os.path.exists(out_file):
        img = cv2.imread(out_file)
    else:
        img = cv2.imread(file_path)
    origin_h = img.shape[0]
    origin_w = img.shape[1]

    dst, r_w, r_h = crop(img, rect, origin_w, origin_h)

    change_size = True
    if is_empty(width) and is_empty(height):
        change_size = False

    if change_size:
        if is_empty(width):
            h = int(height)
            w = round(h * origin_w / origin_h)
        elif is_empty(height):
            w = int(width)
            h = round(w * origin_h / origin_w)
        else:
            w = int(width)
            h = int(height)
        origin = img if dst is None else dst
        dst = cv2.resize(origin, (w, h))
        r_w = w
        r_h = h

    if r_w is None:
        r_w = origin_w
    if r_h is None:
        r_h = origin_h

    if is_empty(flip) is not True:
        flip = int(flip)
        origin = img if dst is None else dst
        dst = cv2.flip(origin, flip)

    if is_empty(rotate) is False and int(rotate) != 0:
        origin = img if dst is None else dst
        dst, new_w, new_h = rot_degree(origin, float(rotate), w=r_w, h=r_h)
        if new_w is not None:
            r_w = new_w
            r_h = new_h

    result_path = file_path

    if dst is not None:
        cv2.imwrite(out_file, dst)
        result_path = out_file
    else:
        dst = img

    if save:
        result_path = get_output_file_path(file_id)
        cv2.imwrite(result_path, dst)

    if is_get:
        mimetype = 'application/octet-stream' if download else 'image/png'
        return send_file(result_path, mimetype=mimetype)

    return jsonify(success_resp({
        "fileId": get_file_id(result_path, True),
        "url": file_url(result_path, True),
        "width": r_w,
        "height": r_h,
    }))


def crop(img, rect: str, w, h):
    # 裁剪,
    # 如果没有改变，返回None
    if is_empty(rect):
        return None, None, None
    r = rect.split(',')
    if len(r) != 4:
        return None, None, None

    left = int(r[0])
    top = int(r[1])
    right = int(r[2])
    bottom = int(r[3])

    if left < 0:
        left = 0
    if right > w:
        right = w
    if top < 0:
        top = 0
    if bottom > h:
        bottom = h

    if left == 0 and top == 0 and right == w and bottom == h:
        return None, None, None

    return img[top:bottom, left:right], right-left, bottom-top


def rot_degree(img, degree, w, h):
    center = (w / 2, h / 2)

    M = cv2.getRotationMatrix2D(center, degree, 1)
    top_right = np.array((w - 1, 0)) - np.array(center)
    bottom_right = np.array((w - 1, h - 1)) - np.array(center)
    top_right_after_rot = M[0:2, 0:2].dot(top_right)
    bottom_right_after_rot = M[0:2, 0:2].dot(bottom_right)
    new_width = max(int(abs(bottom_right_after_rot[0] * 2) + 0.5), int(abs(top_right_after_rot[0] * 2) + 0.5))
    new_height = max(int(abs(top_right_after_rot[1] * 2) + 0.5), int(abs(bottom_right_after_rot[1] * 2) + 0.5))
    offset_x = (new_width - w) / 2
    offset_y = (new_height - h) / 2
    M[0, 2] += offset_x
    M[1, 2] += offset_y
    dst = cv2.warpAffine(img, M, (new_width, new_height))
    return dst, new_width, new_height
