import os
import json

import networkx as nx
from itertools import combinations
from shapely.geometry import Polygon

from data.house import SimpleHouse
from data.geo_tools import get_poly_lines


class CleanCollision(SimpleHouse):
    def __init__(self, plan_data):
        super().__init__(plan_data)
        self.delete_furniture_ids = []
        self.update_furnitures = dict()
        self.plan_data = plan_data

    def clean_collision(self):
        if len(self.rooms) < 1 or len(self.furnitures) < 1:
            print('no rooms or furnitures')
            return self.plan_data
        for rid, fids in self.room2furnitures.items():
            filter_fids = []
            for fid in fids:
                if not self.rooms[rid].covers(self.furnitures[fid]) and \
                        self.furnitures[fid].difference(self.rooms[rid]).area > 10 * max(self.furnitures[fid].size[:2]):
                    self.delete_furniture_ids.append(fid)
                else:
                    filter_fids.append(fid)
            graph = self.get_graph_by_intersects(filter_fids)
            for component in nx.connected_components(graph):
                if len(component) > 1:
                    self.clean_collision_component(component)
        self.update_simple_json()
        return self.plan_data


    def get_graph_by_intersects(self, fids):
        graph = nx.Graph()
        for fid in fids:
            graph.add_node(fid)
        for fi, fj in combinations(fids, 2):
            if self.furnitures[fi].intersects(self.furnitures[fj]):
                graph.add_edge(fi, fj)
        return graph

    def clean_collision_component(self, component):
        fids = list(component)
        fids.sort(key=lambda x: self.furnitures[x].area, reverse=True)
        biggest_furniture = self.furnitures[fids[0]]
        for fid in fids[1:]:
            overlap_furniture = self.furnitures[fid]
            intersection_poly = biggest_furniture.intersection(overlap_furniture)
            if intersection_poly.area / overlap_furniture.area > 0.5:
                self.delete_furniture_ids.append(fid)
            else:
                diff_poly = overlap_furniture.difference(biggest_furniture)
                if not isinstance(diff_poly, Polygon):
                    self.delete_furniture_ids.append(fid)
                    continue
                lines = get_poly_lines(diff_poly)
                if len(lines) != 4:
                    self.delete_furniture_ids.append(fid)
                else:
                    size = list(overlap_furniture.size[:2])
                    min_length = min([line.length for line in lines])
                    max_length = max([line.length for line in lines])

                    if abs(size[0] - min_length) < 1:
                        size[1] = max_length
                    elif abs(size[1] - min_length) < 1:
                        size[0] = max_length
                    elif abs(size[0] - max_length) < 1:
                        size[1] = min_length
                    elif abs(size[1] - max_length) < 1:
                        size[0] = min_length
                    else:
                        print('error')
                        size = (0, 0)
                        self.delete_furniture_ids.append(fid)
                    if size[0] > 0 and size[1] > 0:
                        self.update_furnitures[fid] = {
                            'length': size[0], 'width': size[1],
                            'pos': [*diff_poly.centroid.coords[0][:2], overlap_furniture.height2floor],
                        }

    def update_simple_json(self):
        delete_ids = [int(fid.split('_')[1]) for fid in self.delete_furniture_ids]
        delete_ids.sort(reverse=True)
        for fid, update_info in self.update_furnitures.items():
            fid = int(fid.split('_')[1])
            self.plan_data['furniture'][fid].update(**update_info)
        for fid in delete_ids:
            del self.plan_data['furniture'][fid]



if __name__ == '__main__':
    filename = 'D:\\data\\3D-FRONT-SIMPLE\\faf9f588-42e9-4745-bddd-7d6cbf8c4f99.json'
    with open(filename, 'r', encoding='utf8') as f:
        plan_data = json.load(f)
    clean_collision = CleanCollision(plan_data)
    new_plan_data = clean_collision.clean_collision()
    new_h = SimpleHouse(new_plan_data)
    with open('tmp.json', 'w', encoding='utf8') as f:
        json.dump(new_plan_data, f, ensure_ascii=False)
