import os
from abc import ABC, abstractmethod
from typing import Dict, List, Any, Optional, Tuple
from equipment_calculation.software_types import SoftwareType
from equipment_calculation.find_project_nodes import get_project_divisions_list
from equipment_calculation.quantity_fee_calculator import calculate_quantity_fees as base_calculate_quantity_fees
from equipment_calculation.resource_fee_calculator import calculate_resource_fees as base_calculate_resource_fees
from equipment_calculation.calculation_strategy import CalculationStrategy, DefaultCalculationStrategy
import json


class CalculatorBase(ABC):
    """计算器基类"""

    def __init__(self, software_type: SoftwareType):
        """
        初始化计算器

        Args:
            software_type: 软件类型
        """
        self.software_type = software_type
        self.config_dir = software_type.config_dir
        # 使用默认计算策略
        self.calculation_strategy = self.create_calculation_strategy()
        # 默认输出目录
        self.output_dir = os.path.join("计算结果", self.software_type.name)

    def create_calculation_strategy(self) -> CalculationStrategy:
        """
        创建计算策略

        子类可以重写此方法，返回特定的计算策略实现

        Returns:
            CalculationStrategy: 计算策略实例
        """
        return DefaultCalculationStrategy()

    def get_default_input_file(self) -> str:
        """获取默认输入文件路径"""
        return os.path.join(self.software_type.test_dir)

    def get_output_dir(self) -> str:
        """获取输出目录路径"""
        return self.output_dir

    def set_output_dir(self, output_dir: str) -> None:
        """
        设置输出目录路径

        Args:
            output_dir: 输出目录路径
        """
        self.output_dir = output_dir
        # 如果计算策略支持设置输出目录，也设置计算策略的输出目录
        if hasattr(self.calculation_strategy, "set_output_dir"):
            self.calculation_strategy.set_output_dir(output_dir)

    def calculate_quantity_fee_tables(
        self,
        json_file_path: str,
        project_name: str = None,
    ) -> None:
        """
        计算工程量取费表

        Args:
            json_file_path: JSON文件路径
            project_name: 项目名称，如果为None则处理所有项目
        """
        engineering_type = self.software_type.engineering_type.value + "工程"

        # 在计算前应用软件特定的规则
        preprocess_func = self.apply_quantity_fee_rules()
        if callable(preprocess_func):  # 检查返回值是否可调用
            preprocess_func(json_file_path)  # 调用预处理函数

        if project_name:
            # 处理单个项目划分
            print(f"处理单个项目划分: {project_name}")
            output_file = self._calculate_quantity_fees(json_file_path, project_name, engineering_type)
            if output_file:
                print(f"已完成 {project_name} 的工程量取费表计算，结果保存在 {output_file}")
        else:
            # 处理所有项目划分
            project_divisions = get_project_divisions_list(json_file_path)
            print(f"找到 {len(project_divisions)} 个项目划分节点，开始处理工程量取费表...")

            for i, (proj_name, proj_guid) in enumerate(project_divisions, 1):
                # 使用命令行参数中指定的调差类型，而不是从JSON文件中获取的调差类型
                print(f"处理 {i}/{len(project_divisions)}: {proj_name} (GUID: {proj_guid})")
                output_file = self._calculate_quantity_fees(json_file_path, proj_name, engineering_type, proj_guid)
                if output_file:
                    print(f"已完成 {proj_name} (GUID: {proj_guid}) 的工程量取费表计算")

            print(f"所有项目划分节点的工程量取费表计算完成，结果保存在 {self.get_output_dir()} 目录")

    def calculate_resource_fee_tables(self, json_file_path: str, project_name: str = None) -> None:
        """
        计算人材机合价

        Args:
            json_file_path: JSON文件路径
            project_name: 项目名称，如果为None则处理所有项目
        """
        # 获取工程类型
        engineering_type = self.software_type.engineering_type.value + "工程"

        # 在计算前应用软件特定的规则
        self.apply_resource_fee_rules()

        if project_name:
            # 处理单个项目划分
            output_file = self._calculate_resource_fees(
                json_file_path,
                project_name,
            )
            if output_file:
                print(f"已完成 {project_name} 的人材机合价计算，结果保存在 {output_file}")
        else:
            # 处理所有项目划分
            project_divisions = get_project_divisions_list(json_file_path)
            print(f"找到 {len(project_divisions)} 个项目划分节点，开始处理人材机合价...")

            for i, (proj_name, proj_guid) in enumerate(project_divisions, 1):
                print(f"处理 {i}/{len(project_divisions)}: {proj_name} (GUID: {proj_guid})")
                output_file = self._calculate_resource_fees(json_file_path, proj_name, proj_guid)
                if output_file:
                    print(f"已完成 {proj_name} (GUID: {proj_guid}) 的人材机合价计算")

            print(f"所有项目划分节点的人材机合价计算完成，结果保存在 {self.get_output_dir()} 目录")

    def _calculate_quantity_fees(
        self,
        json_file_path: str,
        project_name: str,
        engineering_type: str,
        project_guid: str = None,
    ) -> str:
        """
        计算工程量取费表，并应用软件特定的后处理规则

        Args:
            json_file_path: JSON文件路径
            project_name: 项目名称
            engineering_type: 工程类型
            project_guid: 项目GUID，用于区分同名项目

        Returns:
            str: 输出文件路径
        """
        # 确保输出目录存在
        os.makedirs(self.get_output_dir(), exist_ok=True)

        # 初始化BCL计算器，传递软件类型和计算类型
        from equipment_calculation.bcl_utils import init_bcl_calculator

        init_bcl_calculator(
            software_category=self.software_type.category.value,
            engineering_type=self.software_type.engineering_type.value,
            calculation_type="工程量",
        )

        # 打印计算策略信息
        print(f"使用计算策略: {self.calculation_strategy.__class__.__name__}")

        # 调用基础计算函数，传入计算策略和项目GUID
        output_file = base_calculate_quantity_fees(
            json_file_path,
            project_name,
            engineering_type,
            project_guid=project_guid,
            calculation_strategy=self.calculation_strategy,
        )

        # 应用软件特定的后处理规则
        if output_file:
            self.post_process_quantity_fees(output_file, project_name)

        return output_file

    def _calculate_resource_fees(
        self,
        json_file_path: str,
        project_name: str,
        project_guid: str = None,
    ) -> str:
        """
        计算人材机合价，并应用软件特定的后处理规则

        Args:
            json_file_path: JSON文件路径
            project_name: 项目名称
            engineering_type: 工程类型
            project_guid: 项目GUID，用于区分同名项目

        Returns:
            str: 输出文件路径
        """
        # 确保输出目录存在
        os.makedirs(self.get_output_dir(), exist_ok=True)

        # 初始化BCL计算器，传递软件类型和计算类型
        from equipment_calculation.bcl_utils import init_bcl_calculator

        init_bcl_calculator(
            software_category=self.software_type.category.value,
            engineering_type=self.software_type.engineering_type.value,
            calculation_type="人材机",
        )

        # 调用基础计算函数，传入计算策略和项目GUID
        output_file = base_calculate_resource_fees(
            json_file_path,
            project_name,
            project_guid=project_guid,
            calculation_strategy=self.calculation_strategy,
        )

        # 应用软件特定的后处理规则
        if output_file:
            self.post_process_resource_fees(output_file, project_name)

        return output_file

    def apply_quantity_fee_rules(self) -> None:
        """应用软件特定的工程量取费规则（在计算前）"""
        pass

    def apply_resource_fee_rules(self) -> None:
        """应用软件特定的人材机合价规则（在计算前）"""
        pass

    def post_process_quantity_fees(self, output_file: str, project_name: str) -> None:
        """
        应用软件特定的工程量取费后处理规则

        Args:
            output_file: 输出文件路径
            project_name: 项目名称
        """
        pass

    def post_process_resource_fees(self, output_file: str, project_name: str) -> None:
        """
        应用软件特定的人材机合价后处理规则

        Args:
            output_file: 输出文件路径
            project_name: 项目名称
        """
        pass
