import pandas as pd
import os
import json
import logging
from typing import Tuple  # 核心：导入大写的Tuple
from src.utils.database import db_instance

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# 【核心修复】计算项目根目录，指向正确的config/settings.json
current_file = os.path.abspath(__file__)  # src/utils/file_importer.py
utils_dir = os.path.dirname(current_file)
src_dir = os.path.dirname(utils_dir)
project_root = os.path.dirname(src_dir)
config_path = os.path.join(project_root, "config", "settings.json")

# 读取配置文件
try:
    with open(config_path, "r", encoding="utf-8") as f:
        CONFIG = json.load(f)
    EXCEL_CONFIG = CONFIG["excel"]
except FileNotFoundError:
    logger.error(f"配置文件不存在: {config_path}")
    raise
except KeyError as e:
    logger.error(f"配置文件格式错误，缺少键: {e}")
    raise
except json.JSONDecodeError:
    logger.error(f"配置文件解析失败，不是有效的JSON格式: {config_path}")
    raise


class ExcelImporter:
    """Excel导入导出工具类，处理学生信息的导入导出"""
    
    def __init__(self):
        # 确保模板目录存在（基于项目根目录拼接）
        self.template_path = os.path.join(project_root, EXCEL_CONFIG["template_path"])
        template_dir = os.path.dirname(self.template_path)
        os.makedirs(template_dir, exist_ok=True)
        # 生成Excel模板
        self._create_template()

    def _create_template(self):
        """创建学生名单Excel模板，包含示例数据指导用户填写"""
        if not os.path.exists(self.template_path):
            # 添加示例数据便于用户理解格式
            template_data = [
                ["学号", "姓名", "专业"],
                ["2023001", "张三", "计算机科学与技术"],
                ["2023002", "李四", "软件工程"]
            ]
            df = pd.DataFrame(template_data[1:], columns=template_data[0])
            try:
                df.to_excel(self.template_path, index=False, engine="openpyxl")
                logger.info(f"Excel模板已生成：{self.template_path}")
            except PermissionError:
                logger.error(f"没有权限写入模板文件：{self.template_path}")
            except Exception as e:
                logger.error(f"生成模板失败：{str(e)}")

    def import_students(self, file_path: str) -> Tuple[bool, str]:  # 修正：Tuple[bool, str]
        """
        从Excel导入学生名单并验证数据合法性
        
        Args:
            file_path: Excel文件路径
            
        Returns:
            Tuple: (是否成功, 结果信息)
        """
        # 基础校验
        if not file_path:
            return False, "文件路径不能为空"
        if not os.path.exists(file_path):
            return False, f"文件不存在：{file_path}"
        if not os.path.isfile(file_path):
            return False, f"不是有效的文件：{file_path}"
        
        try:
            # 读取Excel
            df = pd.read_excel(file_path, engine="openpyxl")
            
            # 列名校验
            required_cols = ["学号", "姓名", "专业"]
            if not all(col in df.columns for col in required_cols):
                missing = [col for col in required_cols if col not in df.columns]
                return False, f"Excel列名错误，缺少必要列：{missing}，需包含：{required_cols}"
            
            # 数据清洗与校验
            # 删除空行（包含NaN的行）
            df = df.dropna(subset=required_cols)
            # 转换为字符串并去除首尾空格
            for col in required_cols:
                df[col] = df[col].astype(str).str.strip()
            
            # 校验空字符串
            empty_rows = df[(df["学号"] == "") | (df["姓名"] == "") | (df["专业"] == "")]
            if not empty_rows.empty:
                return False, f"存在空值数据，行索引：{list(empty_rows.index + 2)}（注意Excel行号从1开始）"
            
            # 校验学号重复
            duplicate_ids = df[df["学号"].duplicated()]["学号"].unique()
            if len(duplicate_ids) > 0:
                return False, f"存在重复学号：{list(duplicate_ids)}"
            
            # 准备导入数据
            students = list(df[required_cols].itertuples(index=False, name=None))
            success_count, fail_list = db_instance.batch_add_students(students)
            
            # 构建返回信息
            result_msg = f"成功导入{success_count}名学生"
            if fail_list:
                # 兼容批量导入的失败详情展示
                fail_details = [f"{s}" for s in fail_list]
                result_msg += f"，失败{len(fail_list)}条：{'; '.join(fail_details)}"
            
            logger.info(result_msg)
            return True, result_msg
            
        except PermissionError:
            return False, f"没有权限读取文件：{file_path}"
        except Exception as e:
            logger.error(f"导入失败：{str(e)}", exc_info=True)
            return False, f"导入失败：{str(e)}"

    def export_scores(self, file_path: str = None) -> Tuple[bool, str]:  # 修正：Tuple[bool, str]
        """
        导出学生积分详单到Excel
        
        Args:
            file_path: 导出文件路径，默认使用配置中的路径
            
        Returns:
            Tuple: (是否成功, 结果信息)
        """
        try:
            # 拼接默认导出路径（基于项目根目录）
            default_export_path = os.path.join(project_root, EXCEL_CONFIG["export_default_path"])
            file_path = file_path or default_export_path
            
            # 确保导出目录存在
            export_dir = os.path.dirname(file_path)
            os.makedirs(export_dir, exist_ok=True)
            
            # 获取学生数据
            students = db_instance.get_all_students()
            if not students:
                return False, "无学生数据可导出"
            
            # 验证数据结构（确保包含所需字段）
            required_fields = 5  # 学号、姓名、专业、总积分、随机点名次数
            if any(len(student) != required_fields for student in students):
                return False, "学生数据结构错误，无法导出"
            
            # 构造DataFrame并导出
            df = pd.DataFrame(students, columns=["学号", "姓名", "专业", "总积分", "随机点名次数"])
            df.to_excel(file_path, index=False, engine="openpyxl")
            
            logger.info(f"积分详单已导出至：{file_path}")
            return True, f"积分详单已导出至：{file_path}"
            
        except PermissionError:
            return False, f"没有权限写入文件：{file_path}"
        except Exception as e:
            logger.error(f"导出失败：{str(e)}", exc_info=True)
            return False, f"导出失败：{str(e)}"


# 单例实例
excel_importer = ExcelImporter()