# ??roi_head??????????????
from torch.utils.data.dataset import T_co

from libs.vision_libs.models.detection import MaskRCNN_ResNet50_FPN_V2_Weights
from models.base.base_dataset import BaseDataset
from torchvision.transforms import  functional as F
import glob
import json
import math
import os
import random
import cv2
import PIL

import matplotlib.pyplot as plt
import matplotlib as mpl
from torchvision.utils import draw_bounding_boxes

import numpy as np
import numpy.linalg as LA
import torch
from skimage import io
from torch.utils.data import Dataset
from torch.utils.data.dataloader import default_collate

import matplotlib.pyplot as plt
from models.dataset_tool import line_boxes, read_masks_from_txt_wire, read_masks_from_pixels_wire, adjacency_matrix

from tools.presets import DetectionPresetTrain


def line_boxes1(target):
    boxs = []
    lines = target.cpu().numpy() * 4

    if len(lines) > 0 and not (lines[0] == 0).all():
        for i, ((a, b)) in enumerate(lines):
            if i > 0 and (lines[i] == lines[0]).all():
                break

            if a[1] > b[1]:
                ymax = a[1] + 10
                ymin = b[1] - 10
            else:
                ymin = a[1] - 10
                ymax = b[1] + 10
            if a[0] > b[0]:
                xmax = a[0] + 10
                xmin = b[0] - 10
            else:
                xmin = a[0] - 10
                xmax = b[0] + 10
            boxs.append([ymin, xmin, ymax, xmax])

    # if boxs == []:
    #     print(target)

    return torch.tensor(boxs)


class WirePointDataset(BaseDataset):
    def __init__(self, dataset_path, transforms=None, dataset_type=None, target_type='pixel'):
        super().__init__(dataset_path)

        self.data_path = dataset_path
        print(f'data_path:{dataset_path}')
        self.transforms = transforms
        self.img_path = os.path.join(dataset_path, "images/" + dataset_type)
        self.lbl_path = os.path.join(dataset_path, "labels/" + dataset_type)
        self.imgs = os.listdir(self.img_path)
        self.lbls = os.listdir(self.lbl_path)
        self.target_type = target_type
        self.transform = MaskRCNN_ResNet50_FPN_V2_Weights.DEFAULT.transforms()
        # self.default_transform = DefaultTransform()

    def __getitem__(self, index) -> T_co:
        img_path = os.path.join(self.img_path, self.imgs[index])
        lbl_path = os.path.join(self.lbl_path, self.imgs[index][:-3] + 'json')

        # img = PIL.Image.open(img_path).convert('RGB')
        img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
        img_rgb=img[:,:,:3]

        print(f'img shape:{img.shape}')
        img_rgb=cv2.cvtColor(img_rgb, cv2.COLOR_BGR2RGB)
        # img=np.array(img,copy=True)
        # img = self.default_transform(img)
        # print(f'pil img:{img.dtype}')
        # w, h = img.size
        # img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
        # cv2.imshow('img',img)
        # cv2.waitKey(1000000)
        # print(img.shape)
        w, h = img.shape[0:2]
        # w, h = img.size
        # wire_labels, target = self.read_target(item=index, lbl_path=lbl_path, shape=(h, w))
        target = self.read_target(item=index, lbl_path=lbl_path, shape=(h, w))

        print(f'self.default_transform:{self.default_transform}')

        # if self.transforms:
        #     img, target = self.transforms(img, target)
        # else:
        #     img = self.default_transform(img)


        # # åç¦»RGBåæ·±åº¦éé
        # rgb_channels = img[:, :, :3]
        # depth_channel = img[:, :, 3]
        #
        # rgb_normalized = rgb_channels/255
        # depth_normalized = (depth_channel - depth_channel.min()) / (depth_channel.max() - depth_channel.min())*255
        #
        # # å°å½ä¸ååçRGBåæ·±åº¦éééæ°ç»å
        # normalized_rgba_image = np.dstack((rgb_normalized, depth_normalized))  # æèä½¿ç¨depth_normalized_fixed_range
        #
        # print("Normalized RGBA image shape:", normalized_rgba_image.shape)
        #
        # img = torch.tensor(normalized_rgba_image,dtype=torch.uint8).permute(2,1,0)


        # cv2.imshow('img',img[:3].permute(1,2,0).numpy().astype(np.uint8))
        # cv2.waitKey(10000000)
        # plt.imshow(img[:3].permute(1,2,0).numpy())
        # plt.show()

        # new_channel = torch.zeros(1, 512, 512)
        # img=torch.cat((img,new_channel),dim=0)
        img=np.dstack((img_rgb,img[:,:,3]))

        img=torch.as_tensor(img).permute(2,0,1)
        img=self.default_transform(img)


        # img=F.convert_image_dtype(img, torch.float)
        print(f'img:{img.shape}')
        # print(f'img dtype:{img.dtype}')
        return img, target

    def __len__(self):
        return len(self.imgs)

    def read_target(self, item, lbl_path, shape, extra=None):
        # print(f'lbl_path:{lbl_path}')
        with open(lbl_path, 'r') as file:
            lable_all = json.load(file)

        n_stc_posl = 300
        n_stc_negl = 40
        use_cood = 0
        use_slop = 0

        wire = lable_all["wires"][0]  # ??
        line_pos_coords = np.random.permutation(wire["line_pos_coords"]["content"])[: n_stc_posl]  # ?????????
        line_neg_coords = np.random.permutation(wire["line_neg_coords"]["content"])[: n_stc_negl]
        npos, nneg = len(line_pos_coords), len(line_neg_coords)
        lpre = np.concatenate([line_pos_coords, line_neg_coords], 0)  # ??????????
        for i in range(len(lpre)):
            if random.random() > 0.5:
                lpre[i] = lpre[i, ::-1]
        ldir = lpre[:, 0, :2] - lpre[:, 1, :2]
        ldir /= np.clip(LA.norm(ldir, axis=1, keepdims=True), 1e-6, None)
        feat = [
            lpre[:, :, :2].reshape(-1, 4) / 128 * use_cood,
            ldir * use_slop,
            lpre[:, :, 2],
        ]
        feat = np.concatenate(feat, 1)

        wire_labels = {
            "junc_coords": torch.tensor(wire["junc_coords"]["content"])[:, :2],
            "jtyp": torch.tensor(wire["junc_coords"]["content"])[:, 2].byte(),
            "line_pos_idx": adjacency_matrix(len(wire["junc_coords"]["content"]), wire["line_pos_idx"]["content"]),
            # ???????????
            "line_neg_idx": adjacency_matrix(len(wire["junc_coords"]["content"]), wire["line_neg_idx"]["content"]),
            # ??????????
            "lpre": torch.tensor(lpre)[:, :, :2],
            "lpre_label": torch.cat([torch.ones(npos), torch.zeros(nneg)]),  # ?????? 1?0
            "lpre_feat": torch.from_numpy(feat),
            "junc_map": torch.tensor(wire['junc_map']["content"]),
            "junc_offset": torch.tensor(wire['junc_offset']["content"]),
            "line_map": torch.tensor(wire['line_map']["content"]),
        }

        labels = []
        #
        # if self.target_type == 'polygon':
        #     labels, masks = read_masks_from_txt_wire(lbl_path, shape)
        # elif self.target_type == 'pixel':
        #     labels = read_masks_from_pixels_wire(lbl_path, shape)

        # print(torch.stack(masks).shape)    # [???, 512, 512]
        target = {}
        # target["labels"] = torch.stack(labels)

        target["image_id"] = torch.tensor(item)
        # return wire_labels, target
        target["wires"] = wire_labels
        # target["boxes"] = line_boxes(target)
        target["boxes"] = line_boxes1(torch.tensor(wire["line_pos_coords"]["content"]))
        target["labels"] = torch.ones(len(target["boxes"]), dtype=torch.int64)
        # print(f'target["labels"]:{ target["labels"]}')
        # print(f'boxes:{target["boxes"].shape}')
        if target["boxes"].numel() == 0:
            print("Tensor is empty")
            print(f'path:{lbl_path}')
        return target

    def show(self, idx):
        image, target = self.__getitem__(idx)

        cmap = plt.get_cmap("jet")
        norm = mpl.colors.Normalize(vmin=0.4, vmax=1.0)
        sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
        sm.set_array([])

        def imshow(im):
            plt.close()
            plt.tight_layout()
            plt.imshow(im)
            plt.colorbar(sm, fraction=0.046)
            plt.xlim([0, im.shape[0]])
            plt.ylim([im.shape[0], 0])

        def draw_vecl(lines, sline, juncs, junts, fn=None):
            img_path = os.path.join(self.img_path, self.imgs[idx])
            imshow(io.imread(img_path))
            if len(lines) > 0 and not (lines[0] == 0).all():
                for i, ((a, b), s) in enumerate(zip(lines, sline)):
                    if i > 0 and (lines[i] == lines[0]).all():
                        break
                    plt.plot([a[1], b[1]], [a[0], b[0]], c="red", linewidth=1)  # a[1], b[1]?????
            if not (juncs[0] == 0).all():
                for i, j in enumerate(juncs):
                    if i > 0 and (i == juncs[0]).all():
                        break
                    plt.scatter(j[1], j[0], c="red", s=2, zorder=100)  # ? s=64

            img_path = os.path.join(self.img_path, self.imgs[idx])
            img = PIL.Image.open(img_path).convert('RGB')
            boxed_image = draw_bounding_boxes((self.default_transform(img) * 255).to(torch.uint8), target["boxes"],
                                              colors="yellow", width=1)
            plt.imshow(boxed_image.permute(1, 2, 0).numpy())
            plt.show()

            plt.show()
            if fn != None:
                plt.savefig(fn)

        junc = target['wires']['junc_coords'].cpu().numpy() * 4
        jtyp = target['wires']['jtyp'].cpu().numpy()
        juncs = junc[jtyp == 0]
        junts = junc[jtyp == 1]

        lpre = target['wires']["lpre"].cpu().numpy() * 4
        vecl_target = target['wires']["lpre_label"].cpu().numpy()
        lpre = lpre[vecl_target == 1]

        # draw_vecl(lpre, np.ones(lpre.shape[0]), juncs, junts, save_path)
        draw_vecl(lpre, np.ones(lpre.shape[0]), juncs, junts)

    def show_img(self, img_path):
        pass

# dataset_train = WirePointDataset("/data/lm/dataset/0424_", dataset_type='val')
# for i in dataset_train:
#     a = 1
