import json
import os

class SceneBasicConverter:
    def save_bin_locations_list(self):
        """
        如果smap文件中有binLocationsList，则单独保存为converted/binLocationsList.json。
        """
        if hasattr(self, 'map_data') and 'binLocationsList' in self.map_data:
            self.ensure_converted_dir()
            filename = f"{self.converted_dir}/binLocationsList.json"
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump({'binLocationsList': self.map_data['binLocationsList']}, f, indent=2, ensure_ascii=False)
            print(f"已单独保存 binLocationsList 到: {filename}")
    def __init__(self, scene_id, setting, ratio):
        self.scene_data = {}
        self.converted_dir = "converted"
        self.scene_data['id'] = scene_id
        self.scene_data['setting'] = setting
        self.scene_data['ratio'] = ratio

    def ensure_converted_dir(self):
        if not os.path.exists(self.converted_dir):
            os.makedirs(self.converted_dir)
            print(f"创建转换结果目录: {self.converted_dir}")

    def save_single_key_json(self, key_name, key_data):
        self.ensure_converted_dir()
        filename = f"{self.converted_dir}/{key_name}.json"
        single_key_data = {key_name: key_data}
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(single_key_data, f, indent=2, ensure_ascii=False)
        print(f"已保存 {key_name} 的独立JSON文件到: {filename}")

    def load_source_files(self, smap_file, scene_file):
        self.smap_file = smap_file
        self.scene_file = scene_file
        if os.path.exists(smap_file):
            with open(smap_file, 'r', encoding='utf-8') as f:
                self.map_data = json.load(f)
        else:
            print(f"警告: 地图文件 {smap_file} 不存在")
            self.map_data = {}
        if os.path.exists(scene_file):
            with open(scene_file, 'r', encoding='utf-8') as f:
                self.scene_source = json.load(f)
        else:
            print(f"警告: 场景文件 {scene_file} 不存在")
            self.scene_source = {}

    def extract_basic_info(self):
        if 'header' in self.map_data:
            header = self.map_data['header']
            self.scene_data['name'] = header.get('mapName', '')
            min_pos = header.get('minPos', {'x': 0, 'y': 0})
            max_pos = header.get('maxPos', {'x': 0, 'y': 0})
            width = max_pos['x'] - min_pos['x']
            height = max_pos['y'] - min_pos['y']
            self.scene_data['width'] = abs(width)
            self.scene_data['height'] = abs(height)
        else:
            raise ValueError("无法计算地图尺寸：map_data中缺少header信息")
        basic_info_data = {
            'id': self.scene_data['id'],
            'name': self.scene_data['name'],
            'width': self.scene_data['width'],
            'height': self.scene_data['height'],
            'setting': self.scene_data['setting'],
            'ratio': self.scene_data['ratio']
        }
        self.save_single_key_json('basic_info', basic_info_data)

    def extract_coordinate_system(self):
        if self.scene_source:
            self.scene_data['scale'] = self.scene_source.get('scale', 0.6599999999999997)
            self.scene_data['origin'] = self.scene_source.get('origin', {
                'x': -3679.5080777864587,
                'y': -3925.231448210223
            })
        else:
            self.scene_data['scale'] = 0.6599999999999997
            self.scene_data['origin'] = {
                'x': -3679.5080777864587,
                'y': -3925.231448210223
            }
        coordinate_data = {
            'scale': self.scene_data['scale'],
            'origin': self.scene_data['origin']
        }
        self.save_single_key_json('coordinate_system', coordinate_data)

    def extract_robots(self):
        # 无论源数据如何，robots 字段都输出空列表
        self.scene_data['robots'] = []
        self.save_single_key_json('robots', self.scene_data['robots'])

    def extract_points(self):
        if 'advancedPointList' in self.map_data:
            self.scene_data['points'] = self.extract_advanced_points()
        elif self.scene_source and 'points' in self.scene_source:
            self.scene_data['points'] = self.scene_source['points']
        else:
            self.scene_data['points'] = []
        self.save_single_key_json('points', self.scene_data['points'])

    def extract_advanced_points(self):
        points = []
        if 'advancedPointList' in self.map_data:
            advanced_points = self.map_data['advancedPointList']
            for i, point in enumerate(advanced_points):
                point_id = str(10000001 + i)
                name = point.get('instanceName', f'Point{i+1}')
                pos = point.get('pos', {})
                x = pos.get('x', 0)
                y = pos.get('y', 0)
                className = point.get('className', 'ActionPoint')
                point_type = self.get_point_type_by_class(className)
                properties = []
                if 'property' in point:
                    for prop in point['property']:
                        property_obj = {
                            "key": prop.get('key', ''),
                            "type": prop.get('type', ''),
                            "value": prop.get('value', ''),
                            "boolValue": prop.get('boolValue', False)
                        }
                        prop_type = prop.get('type', '')
                        if prop_type == 'bool':
                            property_obj["boolValue"] = prop.get('boolValue', False)
                        elif prop_type == 'string':
                            property_obj["stringValue"] = prop.get('stringValue', '')
                        elif prop_type == 'int32':
                            property_obj["int32Value"] = prop.get('int32Value', 0)
                        elif prop_type == 'float':
                            property_obj["floatValue"] = prop.get('floatValue', 0.0)
                        properties.append(property_obj)
                point_obj = {
                    "id": point_id,
                    "name": name,
                    "x": x,
                    "y": y,
                    "type": point_type,
                    "config": {},
                    "properties": properties,
                    "associatedStorageLocations": [],
                    "robots": [],
                    "enabled": 1
                }
                points.append(point_obj)
        return points

    def get_point_type_by_class(self, className):
        type_mapping = {
            'LocationMark': 1,
            'ParkPoint': 14,
            'SwitchMap': 5,
            'HomeRegion': 2,
            'ActionPoint': 15,
            'TransferLocation': 14,
            'WorkingLocation': 16,
            'ChargePoint': 13
        }
        if className not in type_mapping:
            if className.startswith('LM'):
                return 1
            elif className.startswith('PP'):
                return 14
            elif className.startswith('SW'):
                return 5
            elif className.startswith('HR'):
                return 2
            elif className.startswith('AP'):
                return 15
            elif className.startswith('TL'):
                return 14
            elif className.startswith('WL'):
                return 16
            elif className.startswith('CP'):
                return 13
            else:
                return 1
        return type_mapping.get(className, 15)

    def extract_routes(self):
        self.scene_data['routes'] = self.extract_advanced_curves()
        self.save_single_key_json('routes', self.scene_data['routes'])

    def extract_advanced_curves(self):
        routes = []
        name_to_id_map = {}
        points_file = f"{self.converted_dir}/points.json"
        if os.path.exists(points_file):
            try:
                with open(points_file, 'r', encoding='utf-8') as f:
                    points_data = json.load(f)
                    if 'points' in points_data:
                        for point in points_data['points']:
                            name_to_id_map[point['name']] = point['id']
            except Exception as e:
                print(f"警告: 无法读取 {points_file} 文件: {e}")
        else:
            print(f"警告: 站点文件 {points_file} 不存在，无法建立映射关系")
        curve_data = self.map_data
        if 'advancedCurveList' in curve_data:
            advanced_curves = curve_data['advancedCurveList']
            print(f"找到 {len(advanced_curves)} 条路径数据")
            # 路径类型映射表，优先用className判断
            path_type_map = {
                "StraightPath": "line",
                "BezierPath": "BezierPath",
                "ArcPath": "bezier2",
                "DegenerateBezier": "bezier3",
                "NURBS6": "NURBS6"
            }
            for i, curve in enumerate(advanced_curves):
                route_id = str(100000 + i)
                desc = curve.get('instanceName', f'Route{i+1}')
                start_pos = curve.get('startPos', {})
                end_pos = curve.get('endPos', {})
                from_instance_name = start_pos.get('instanceName', '')
                to_instance_name = end_pos.get('instanceName', '')
                from_point = name_to_id_map.get(from_instance_name, from_instance_name)
                to_point = name_to_id_map.get(to_instance_name, to_instance_name)
                if from_instance_name not in name_to_id_map:
                    print(f"警告: 找不到起点 '{from_instance_name}' 的映射")
                if to_instance_name not in name_to_id_map:
                    print(f"警告: 找不到终点 '{to_instance_name}' 的映射")
                control_pos1 = curve.get('controlPos1', {})
                control_pos2 = curve.get('controlPos2', {})
                control_pos3 = curve.get('controlPos3', {})
                control_pos4 = curve.get('controlPos4', {})
                properties = []
                if 'property' in curve:
                    for prop in curve['property']:
                        properties.append({
                            "key": prop.get('key', ''),
                            "type": prop.get('type', ''),
                            "value": prop.get('value', ''),
                            "int32Value": prop.get('int32Value', 0),
                            "boolValue": prop.get('boolValue', False)
                        })
                # 优先用className判断路径类型
                class_name = curve.get('className', '')
                curve_type = curve.get('type', '')
                mapped_type = path_type_map.get(class_name, path_type_map.get(curve_type, "bezier3"))
                route_obj = {
                    "id": route_id,
                    "desc": desc,
                    "from": from_point,
                    "to": to_point,
                    "type": mapped_type,
                    "pass": 0,
                    "config": {},
                    "properties": properties
                }
                # 按类型添加controlPos字段，直线不添加c1/c2
                if mapped_type == "BezierPath" or mapped_type == "bezier3":
                    route_obj["c1"] = {"x": control_pos1.get('x', 0), "y": control_pos1.get('y', 0)}
                    route_obj["c2"] = {"x": control_pos2.get('x', 0), "y": control_pos2.get('y', 0)}
                elif mapped_type == "bezier2":
                    route_obj["c1"] = {"x": control_pos1.get('x', 0), "y": control_pos1.get('y', 0)}
                elif mapped_type == "NURBS6":
                    route_obj["c1"] = {"x": control_pos1.get('x', 0), "y": control_pos1.get('y', 0), "z": control_pos1.get('z', 0)}
                    route_obj["c2"] = {"x": control_pos2.get('x', 0), "y": control_pos2.get('y', 0), "z": control_pos2.get('z', 0)}
                    route_obj["c3"] = {"x": control_pos3.get('x', 0), "y": control_pos3.get('y', 0), "z": control_pos3.get('z', 0)}
                    route_obj["c4"] = {"x": control_pos4.get('x', 0), "y": control_pos4.get('y', 0), "z": control_pos4.get('z', 0)}
                # 直线（line）不添加c1/c2等字段
                routes.append(route_obj)
            print(f"成功生成 {len(routes)} 条路径")
        else:
            print("警告: 未找到advancedCurveList数据")
        return routes

    def extract_bin_locations(self):
        """
        优先从converted/binLocationsList.json读取binLocationsList，否则从map_data中读取并保存。
        """
        import os
        filename = f"{self.converted_dir}/binLocationsList.json"
        bin_locations = None
        if os.path.exists(filename):
            with open(filename, 'r', encoding='utf-8') as f:
                data = json.load(f)
                bin_locations = data.get('binLocationsList', [])
        else:
            bin_locations = self.map_data.get('binLocationsList', [])
        self.scene_data['binLocationsList'] = bin_locations
        self.save_single_key_json('binLocationsList', self.scene_data['binLocationsList'])

    def convert_basic(self, smap_file, scene_file, output_file="converted_scene.scene"):
        print(f"开始基本信息转换...")
        print(f"源地图文件: {smap_file}")
        print(f"源场景文件: {scene_file}")
        print(f"输出文件: {output_file}")
        print("-" * 50)
        self.load_source_files(smap_file, scene_file)
        self.save_bin_locations_list()
        self.extract_basic_info()
        self.extract_coordinate_system()
        self.extract_robots()
        self.extract_points()
        self.extract_routes()
        self.extract_bin_locations()

        # 获取所有一级key
        all_keys = [
            'id', 'setting', 'ratio', 'name', 'width', 'height', 'scale', 'origin',
            'robotGroups', 'robots', 'points', 'routes', 'areas', 'blocks', 'binLocationsList'
        ]
        # 补全缺失的一级key，值为空（空列表、空字典或空字符串）
        for key in all_keys:
            if key not in self.scene_data:
                if key in ['robotGroups', 'robots', 'points', 'routes', 'areas', 'binLocationsList']:
                    self.scene_data[key] = []
                elif key in ['origin', 'scale']:
                    self.scene_data[key] = {} if key == 'origin' else 0
                elif key in ['blocks']:
                    self.scene_data[key] = ""
                else:
                    self.scene_data[key] = ""

        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(self.scene_data, f, indent=2, ensure_ascii=False)
        print(f"基本信息转换完成！结果已保存到 {output_file}")
        return self.scene_data

