# -*- coding: utf-8 -*-
from io import BytesIO
from traceback import format_exc

import cv2
import requests
from PIL import Image, ImageDraw, ImageFont
import numpy as np
from loguru import logger

from enums.ExceptionEnum import ExceptionType
from exception.CustomerException import ServiceException

'''
    文字水印
'''


class TextWaterMark():
    def __init__(self):
        self.color_dict = {
            # R G B
            # 网址查看：https://tool.oschina.net/commons?type=3
            # 网址查看：http://tools.jb51.net/static/colorpicker/
            'white': (255, 255, 255, 255),
            'black': (0, 0, 0, 255),
            'gray': (205, 201, 201, 255),
            'red': (255, 0, 0, 255),
            'yellow': (255, 215, 0, 255),
            'blue': (0, 0, 170, 255),
            'purple': (205, 105, 201, 255),
            'green': (0, 205, 0, 255)
        }
        self.position_list = [1, 2, 3, 4]

    """
        普通照片水印
        params:
            image:图片
            text:水印文字
            position:水印位置
                    1：左上
                    2：右上
                    3：右下
                    4：左下
            fontface: 字体        
            fontsize:字体大小
            fontcolor:字体颜色
                    [white, black, gray, red, yellow, blue, purple, green]
    """

    def common_water(self, image, text, position=1, fontface='../font/simsun.ttc', fontsize=20, fontcolor='black'):
        flag = False
        if isinstance(image, np.ndarray):  # 判断是否OpenCV图片类型
            flag = True
            image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA))
        if position not in self.position_list:
            position = 1
        w, h = image.size[:2]
        keys = self.color_dict.keys()
        if fontcolor not in keys:
            fontcolor = 'black'
        color = self.color_dict[fontcolor]
        fnt = ImageFont.truetype(fontface, fontsize)
        im = image.convert('RGBA')
        mask = Image.new('RGBA', im.size, (0, 0, 0, 0))
        d = ImageDraw.Draw(mask)
        size_w, size_h = d.textsize(text, font=fnt)
        if position == 1:
            weizhi = (w * 0.1, h * 0.1)
        elif position == 2:
            weizhi = (w * 0.9 - size_w, h * 0.1)
        elif position == 3:
            weizhi = (w * 0.9 - size_w, h * 0.9 - size_h)
        else:
            weizhi = (w * 0.1, h * 0.9 - size_h)
        # position 为左上角位置
        d.text(weizhi, text, font=fnt, fill=color)
        out = Image.alpha_composite(im, mask)
        if flag:
            out = cv2.cvtColor(np.asarray(out), cv2.COLOR_BGRA2RGBA)
        return out

    """
        半透明水印，布满整张图，并且自动旋转45°
        params:
            image:图片
            text:文字
            fontsize:文字大小
    """

    def fill_water(self, image, text, fontsize):
        flag = False
        if isinstance(image, np.ndarray):  # 判断是否OpenCV图片类型
            flag = True
            image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA))
        font = ImageFont.truetype('../font/simsun.ttc', fontsize)
        # 添加背景
        new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (255, 255, 255, 255))
        new_img.paste(image, image.size)

        # 添加水印
        font_len = len(text)
        rgba_image = new_img.convert('RGBA')
        text_overlay = Image.new('RGBA', rgba_image.size, (0, 0, 0, 0))
        image_draw = ImageDraw.Draw(text_overlay)

        for i in range(0, rgba_image.size[0], font_len * 40 + 100):
            for j in range(0, rgba_image.size[1], 200):
                # print(f'i:{i}, j:{j}, text:{text}, font:{font}')
                image_draw.text((i, j), text, font=font, fill=(0, 0, 0, 50))
        text_overlay = text_overlay.rotate(-45)
        image_with_text = Image.alpha_composite(rgba_image, text_overlay)

        image_with_text = image_with_text.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2))
        if flag:
            image_with_text = cv2.cvtColor(np.asarray(image_with_text), cv2.COLOR_BGRA2RGBA)
        return image_with_text


class PictureWaterMark:
    __slots__ = ('logo', '__requestId')

    def __init__(self, logo=None, requestId=None):
        self.__requestId = requestId
        self.logo = logo
        if requestId is None:
            self.__requestId = '1'
        if logo is None:
            self.logo = cv2.imread("./image/logo.png", -1)

    # def common_water(self, image, logo):
    #     width, height = image.shape[1], image.shape[0]
    #     mark_width, mark_height = logo.shape[1], logo.shape[0]
    #     rate = int(width * 0.2) / mark_width
    #     logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST)
    #     position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0]))
    #     b = Image.new('RGBA', (width, height), (0, 0, 0, 0))  # 创建新图像：透明'
    #     a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    #     watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA))
    #     # 图片旋转
    #     # watermark = watermark.rotate(45)
    #     b.paste(a, (0, 0))
    #     b.paste(watermark, position, mask=watermark)
    #     return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB)

    def common_water_1(self, image, logo, alpha=1):
        try:
            h, w = image.shape[0], image.shape[1]
            # if w >= h:
            rate = int(w * 0.1) / logo.shape[1]
            # else:
            #     rate = int(h * 0.1) / logo.shape[0]
            mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST)
            mask_h, mask_w = mask.shape[0], mask.shape[1]
            mask_channels = cv2.split(mask)
            dst_channels = cv2.split(image)
            # b, g, r, a = cv2.split(mask)
            # 计算mask在图片的坐标
            # if w >= h:
            ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
            dr_points = (int(h * 0.95), int(w - h * 0.05))
            # else:
            #     ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
            #     dr_points = (int(h * 0.95), int(w - h * 0.05))
            for i in range(3):
                dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][
                                                                                          ul_points[0]: dr_points[0],
                                                                                          ul_points[1]: dr_points[
                                                                                              1]] * (
                                                                                                  255.0 - mask_channels[
                                                                                              3] * alpha) / 255
                dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array(
                    mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8)
            dst_img = cv2.merge(dst_channels)
            return dst_img
        except Exception:
            logger.error("加水印异常:{}, requestId:{}", format_exc(), self.__requestId)
            return image


def add_water_pic(image, logo, requestId, alpha=1):
    try:
        h, w = image.shape[0], image.shape[1]
        # if w >= h:
        rate = int(w * 0.1) / logo.shape[1]
        # else:
        #     rate = int(h * 0.1) / logo.shape[0]
        mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST)
        mask_h, mask_w = mask.shape[0], mask.shape[1]
        mask_channels = cv2.split(mask)
        dst_channels = cv2.split(image)
        # b, g, r, a = cv2.split(mask)
        # 计算mask在图片的坐标
        # if w >= h:
        ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
        dr_points = (int(h * 0.95), int(w - h * 0.05))
        # else:
        #     ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
        #     dr_points = (int(h * 0.95), int(w - h * 0.05))
        for i in range(3):
            dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][
                                                                                      ul_points[0]: dr_points[0],
                                                                                      ul_points[1]: dr_points[
                                                                                          1]] * (
                                                                                              255.0 - mask_channels[
                                                                                          3] * alpha) / 255
            dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array(
                mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8)
        dst_img = cv2.merge(dst_channels)
        return dst_img
    except Exception:
        logger.error("加水印异常:{}, requestId:{}", format_exc(), requestId)
        return image


# 差值感知算法
def dHash(image):
    # 缩放9*8
    image = cv2.resize(image, (9, 8), interpolation=cv2.INTER_CUBIC)
    # 转换灰度图
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    #     print(image.shape)
    hash = []
    # 每行前一个像素大于后一个像素为1，相反为0，生成哈希
    for i in range(8):
        for j in range(8):
            if image[i, j] > image[i, j + 1]:
                hash.append(1)
            else:
                hash.append(0)
    return hash


# 计算汉明距离
def Hamming_distance(hash1, hash2):
    num = 0
    for index in range(len(hash1)):
        if hash1[index] != hash2[index]:
            num += 1
    return num


def url2Array(url, enable_ex=True):
    try:
        response = requests.get(url)
        image = Image.open(BytesIO(response.content))
        image1 = np.array(image)
        img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR)
        return img_bgr
    except Exception:
        logger.exception("url地址请求异常: {}", format_exc())
        if enable_ex:
            raise ServiceException(ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0],
                                   ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1])
        return None


def url2Content(url):
    response = requests.get(url)
    return response.content


def url2Image(url):
    response = requests.get(url)
    image = Image.open(BytesIO(response.content))
    image1 = np.array(image)
    img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR)
    img = Image.fromarray(img_bgr)
    return img


def url2Byte(url):
    response = requests.get(url)
    return BytesIO(response.content)


def markRectangle(url, text, textCoordinate, imageLeftUpCoordinate, imageRightDownCoordinate, color):
    img = url2Array(url)
    # ( 蓝, 绿, 红)
    # 红色 (0, 0, 255)
    # 洋红色 (255, 0, 255)
    # 青色 (255, 255, 0)
    # 黑色 (0, 0, 0)
    # 蓝色 (255, 0, 0)
    # 绿色 (0, 255, 0)
    # 黄色 (0, 255, 255) # 不考虑
    cv2.putText(img, text, textCoordinate, cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 1, cv2.LINE_AA)
    # rectangle 坐标的参数格式为左上角（x1, y1），右下角（x2, y2）, 颜色 , 粗细
    cv2.rectangle(img, imageLeftUpCoordinate, imageRightDownCoordinate, color, 2)
    return img


# def draw_painting_joint(img,  xywh, score=0.5, color=None,
#                         font={'line_thickness': None, 'boxLine_thickness': None, 'fontSize': None}):
#     imh, imw, imc = img.shape
#     tl = font['line_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1
#     box_tl = font['boxLine_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # 根据图像的尺寸计算出适合用于绘制图像边框的线宽。
#     c1, c2 = (int(xywh[0]), int(xywh[1])), (int(xywh[2]), int(xywh[3]))
#     cv2.rectangle(img, c1, c2, color, thickness=box_tl, lineType=cv2.LINE_AA)
#
#     label = ' %.2f' % (score)
#     tf = max(tl, 1)  # font thickness
#     fontScale = font['fontSize'] or tl * 0.33
#     t_size = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0]
#     cv2.rectangle(img, (int(box[0]) + lw, int(box[1])), c2, color, -1, cv2.LINE_AA)  # filled
#     cv2.putText(img, label, (c1[0] + lw, c1[1] - (lh - t_size[1]) // 2), 0, fontScale, [225, 255, 255], thickness=tf,
#                 lineType=cv2.LINE_AA)
#     # print('#####line224 fontScale:',fontScale,'  thickness:',tf,'   line_thickness:',font['line_thickness'],' boxLine thickness:',box_tl)
#     return img


def img_pad(img, size, pad_value=[114, 114, 114]):
    ###填充成固定尺寸
    H, W, _ = img.shape
    r = max(H / size[0], W / size[1])
    img_r = cv2.resize(img, (int(W / r), int(H / r)))
    tb = size[0] - img_r.shape[0]
    lr = size[1] - img_r.shape[1]
    top = int(tb / 2)
    bottom = tb - top
    left = int(lr / 2)
    right = lr - left
    pad_image = cv2.copyMakeBorder(img_r, top, bottom, left, right, cv2.BORDER_CONSTANT, value=pad_value)
    return pad_image, (top, left, r)


def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
    # 调整图像大小和填充图像，同时满足步幅多重约束
    shape = img.shape[:2]  # current shape [height, width] 当前形状 [高度、宽度]
    if isinstance(new_shape, int):
        new_shape = (new_shape, new_shape)

    # Scale ratio (new / old) 缩放比例（新/旧）
    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
    if not scaleup:  # 仅缩减，不纵向扩展（为了更好的测试 mAP）
        r = min(r, 1.0)

    ratio = r, r  # width, height ratios 宽度、高度比
    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  # wh padding
    if auto:  # 最小矩形
        dw, dh = np.mod(dw, stride), np.mod(dh, stride)  # wh padding
    elif scaleFill:  # stretch
        dw, dh = 0.0, 0.0
        new_unpad = (new_shape[1], new_shape[0])
        ratio = new_shape[1] / shape[1], new_shape[0] / shape[0]  # width, height ratios

    dw /= 2  # divide padding into 2 sides
    dh /= 2

    if shape[::-1] != new_unpad:  # resize
        img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
    img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border
    return img, ratio, (dw, dh)

# if __name__ == '__main__':
#     # img = cv2.imread("../test/a.jpg", -1)
#     # fontcolor = 'yellow'
#     #
#     # water = TextWaterMark()
#     # text = "hello world"
#     #
#     # # fill_img = water.common_water(img, text, position=4, fontface='../font/庞门正道标题体2.0增强版.ttf', fontsize=20, fontcolor='black')
#     # fill_img = water.fill_water(img, text, 20)
#     # # 一定要保存为png格式
#     # cv2.imshow('result', fill_img)
#     # cv2.waitKey(111111110)
#     # print('finish')
#     pic = PictureWaterMark()
#     image = cv2.imread("a.jpg")
#     logo = cv2.imread("../image/logo.png", -1)
#     # print(image, logo)
#     start = time.time()
#     frame = pic.common_water(image, logo)
#     print(time.time() - start)
#     start1 = time.time()
#     frame1 = pic.common_water_1(image, logo)
#     # cv2.imwrite("watermarked.jpg", frame1)
#     print(time.time() - start1)
#     # cap = cv2.VideoCapture("../data/111111.mp4")
#     # logo = cv2.imread("../image/logo.png", -1)
#     # while True:
#     #         is_opened, frame = cap.read()
#     #         frame = pic.common_water(frame, logo)
#     #         cv2.imshow('frame', frame)
#     #         cv2.waitKey(1)  # 等待输入任何按键
#     # # 关闭
#     # cap.release()
