import geopandas as gpd

from collections import defaultdict, namedtuple
from shapely.geometry import Polygon
from .geo_tools import get_poly, angle2direction


CustPoly = namedtuple('CustPoly', ['poly', 'id', 'size', 'angle', 'direction', 'height2floor', 'category'])
Room = namedtuple('Room', ['poly', 'id', 'name', 'room_type', 'doors', 'windows'])


def get_cust_poly(poly_data, poly_id):
    poly = get_poly(poly_data)
    cust_poly = CustPoly(poly, poly_id, (poly_data['length'], poly_data['width'], poly_data.get('height')), poly_data['rotate'],
                         angle2direction(poly_data['rotate']+90), poly_data['pos'][2], poly_data['type'])
    return cust_poly


class SimpleHouse:
    def __init__(self, plan_data):
        self.rooms = dict()
        self.out_room = None
        self.doors = dict()
        self.windows = dict()
        self.furnitures = dict()
        self.room2furnitures = defaultdict(list)
        self.door2rooms = defaultdict(list)
        self.get_rooms(plan_data)
        self.get_win_doors(plan_data)
        self.get_furnitures(plan_data)
        self.attach_win_door2room()
        self.get_furniture_room_map()

    def get_rooms(self, plan_data):
        for room_data in plan_data['rooms']:
            room = Room(Polygon(room_data['wallPoints']), room_data['roomId'], room_data['roomName'], room_data['roomType'], [], [])
            if room_data['roomType'] > 0:
                self.rooms[room_data['roomId']] = room
            else:
                self.out_room = room

    def get_win_doors(self, plan_data):
        for i, win_door in enumerate(plan_data['windowsDoors']):
            win_door_id = f'{i}'
            poly = get_cust_poly(win_door, win_door_id)
            if win_door['type'] == 'door':
                self.doors[win_door_id] = poly
            else:
                self.windows[win_door_id] = poly

    def get_furnitures(self, plan_data):
        for i, furniture in enumerate(plan_data['furniture']):
            f_id = f'furniture_{i}'
            poly = get_cust_poly(furniture, f_id)
            self.furnitures[f_id] = poly

    def get_furniture_room_map(self):
        for fid, furniture in self.furnitures.items():
            for rid, room in self.rooms.items():
                if room.poly.covers(furniture.poly.centroid):
                    self.room2furnitures[rid].append(fid)
                    break
            else:
                distances = [(room.poly.distance(furniture.poly.centroid), rid) for rid, room in self.rooms.items()]
                self.room2furnitures[min(distances)[1]].append(fid)

    def attach_win_door2room(self):
        for did, door in self.doors.items():
            for room in self.rooms.values():
                if room.poly.distance(door.poly.centroid) <= 0.6 * door.size[1]:
                    room.doors.append(did)
                    self.door2rooms[did].append(room.id)
        for wid, win in self.windows.items():
            for room in self.rooms.values():
                if room.poly.distance(win.poly.centroid) <= 0.6 * win.size[1]:
                    room.windows.append(wid)


def plot_polys(ax, polys, colors, alpha=0.1):
    if polys is None:
        polys = []
    if len(polys) < 1:
        return
    gpdf = gpd.GeoDataFrame({'geometry': polys})
    gpdf.plot(ax=ax, color=colors, alpha=alpha, aspect='equal', edgecolor='black')
