package com.ruoyi.framework.security.validator;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import com.ruoyi.common.exception.DepartmentAccessDeniedException;
import com.ruoyi.common.exception.DepartmentDataInconsistencyException;
import com.ruoyi.framework.security.context.DepartmentContextHolder;

/**
 * 部门权限验证器
 * 
 * 负责验证用户对数据的访问权限，确保用户只能访问和操作属于自己部门的数据。
 * 同时处理数据创建时的部门自动设置和关联数据的部门一致性验证。
 * 
 * @author ruoyi
 */
@Component
public class DepartmentPermissionValidator
{
    private static final Logger log = LoggerFactory.getLogger(DepartmentPermissionValidator.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 业务表与主键字段的映射关系
     */
    private static final Map<String, String> TABLE_PRIMARY_KEY_MAP = new HashMap<>();
    
    static {
        TABLE_PRIMARY_KEY_MAP.put("dc_contract", "contract_id");
        TABLE_PRIMARY_KEY_MAP.put("dc_service_contract", "contract_id");
        TABLE_PRIMARY_KEY_MAP.put("dc_service_period", "period_id");
        TABLE_PRIMARY_KEY_MAP.put("dc_employee_info", "employee_id");
        TABLE_PRIMARY_KEY_MAP.put("dc_employee_library", "library_id");
        TABLE_PRIMARY_KEY_MAP.put("dc_credit", "credit_id");
        TABLE_PRIMARY_KEY_MAP.put("dc_bank_institution", "bank_id");
        TABLE_PRIMARY_KEY_MAP.put("dc_financing", "financing_id");
    }

    /**
     * 验证用户对指定记录的访问权限
     * 
     * @param recordId 记录ID
     * @param tableName 表名
     * @throws DepartmentAccessDeniedException 当用户无权访问该记录时抛出
     */
    public void validateDataAccess(Long recordId, String tableName)
    {
        if (recordId == null || tableName == null)
        {
            log.warn("记录ID或表名为空，跳过权限验证");
            return;
        }

        // 超级管理员跳过验证
        if (DepartmentContextHolder.isSuperAdmin())
        {
            log.debug("超级管理员访问数据，跳过部门权限验证");
            return;
        }

        Long recordDeptId = getRecordDeptId(recordId, tableName);
        Long userDeptId = DepartmentContextHolder.getCurrentDeptId();

        if (recordDeptId == null)
        {
            log.warn("无法获取记录的部门ID，表: {}, 记录ID: {}", tableName, recordId);
            throw new DepartmentAccessDeniedException("数据记录缺少部门信息");
        }

        if (userDeptId == null)
        {
            log.warn("无法获取当前用户的部门ID");
            throw new DepartmentAccessDeniedException("用户部门信息缺失");
        }

        if (!Objects.equals(recordDeptId, userDeptId))
        {
            log.warn("用户尝试访问其他部门的数据，用户部门: {}, 记录部门: {}, 表: {}, 记录ID: {}", 
                    userDeptId, recordDeptId, tableName, recordId);
            throw new DepartmentAccessDeniedException("无权访问其他部门的数据");
        }

        log.debug("部门权限验证通过，用户部门: {}, 记录部门: {}", userDeptId, recordDeptId);
    }

    /**
     * 验证数据创建权限并自动设置部门ID
     * 
     * @param entity 要创建的实体对象
     * @throws DepartmentAccessDeniedException 当无法设置部门ID时抛出
     */
    public void validateDataCreation(Object entity)
    {
        if (entity == null)
        {
            log.warn("实体对象为空，跳过部门设置");
            return;
        }

        // 超级管理员可以创建任意部门的数据，但仍需要设置部门ID
        Long deptId = DepartmentContextHolder.getCurrentDeptId();
        if (deptId == null)
        {
            log.error("无法获取当前用户的部门ID，无法创建数据");
            throw new DepartmentAccessDeniedException("用户部门信息缺失，无法创建数据");
        }

        // 自动设置实体的部门ID
        setEntityDeptId(entity, deptId);
        
        log.debug("为新创建的实体设置部门ID: {}, 实体类型: {}", deptId, entity.getClass().getSimpleName());
    }

    /**
     * 验证关联数据的部门一致性
     * 
     * @param primaryTableName 主表名
     * @param primaryRecordId 主记录ID
     * @param relatedTableName 关联表名
     * @param relatedRecordId 关联记录ID
     * @throws DepartmentDataInconsistencyException 当关联数据部门不一致时抛出
     */
    public void validateRelatedDataConsistency(String primaryTableName, Long primaryRecordId, 
                                             String relatedTableName, Long relatedRecordId)
    {
        if (primaryRecordId == null || relatedRecordId == null)
        {
            log.warn("主记录ID或关联记录ID为空，跳过一致性验证");
            return;
        }

        // 超级管理员跳过验证
        if (DepartmentContextHolder.isSuperAdmin())
        {
            log.debug("超级管理员操作，跳过关联数据一致性验证");
            return;
        }

        Long primaryDeptId = getRecordDeptId(primaryRecordId, primaryTableName);
        Long relatedDeptId = getRecordDeptId(relatedRecordId, relatedTableName);

        if (primaryDeptId == null || relatedDeptId == null)
        {
            log.warn("无法获取记录的部门ID，主表: {}, 主记录ID: {}, 关联表: {}, 关联记录ID: {}", 
                    primaryTableName, primaryRecordId, relatedTableName, relatedRecordId);
            throw new DepartmentDataInconsistencyException("关联数据缺少部门信息");
        }

        if (!Objects.equals(primaryDeptId, relatedDeptId))
        {
            log.error("关联数据部门不一致，主表: {} (部门: {}), 关联表: {} (部门: {})", 
                     primaryTableName, primaryDeptId, relatedTableName, relatedDeptId);
            throw new DepartmentDataInconsistencyException(
                String.format("关联数据部门不一致，%s的部门为%d，%s的部门为%d", 
                             primaryTableName, primaryDeptId, relatedTableName, relatedDeptId));
        }

        log.debug("关联数据部门一致性验证通过，部门ID: {}", primaryDeptId);
    }

    /**
     * 获取记录的部门ID
     * 
     * @param recordId 记录ID
     * @param tableName 表名
     * @return 部门ID，如果查询失败返回null
     */
    private Long getRecordDeptId(Long recordId, String tableName)
    {
        try
        {
            String primaryKey = TABLE_PRIMARY_KEY_MAP.get(tableName);
            if (primaryKey == null)
            {
                log.warn("未知的表名: {}", tableName);
                return null;
            }

            String sql = String.format("SELECT dept_id FROM %s WHERE %s = ?", tableName, primaryKey);
            return jdbcTemplate.queryForObject(sql, Long.class, recordId);
        }
        catch (Exception e)
        {
            log.error("查询记录部门ID失败，表: {}, 记录ID: {}", tableName, recordId, e);
            return null;
        }
    }

    /**
     * 为实体对象设置部门ID
     * 
     * @param entity 实体对象
     * @param deptId 部门ID
     */
    private void setEntityDeptId(Object entity, Long deptId)
    {
        try
        {
            Field deptIdField = findDeptIdField(entity.getClass());
            if (deptIdField != null)
            {
                deptIdField.setAccessible(true);
                deptIdField.set(entity, deptId);
                log.debug("成功设置实体部门ID: {}", deptId);
            }
            else
            {
                log.warn("实体类 {} 中未找到dept_id字段", entity.getClass().getSimpleName());
            }
        }
        catch (Exception e)
        {
            log.error("设置实体部门ID失败", e);
            throw new DepartmentAccessDeniedException("设置部门信息失败");
        }
    }

    /**
     * 查找实体类中的dept_id字段
     * 
     * @param clazz 实体类
     * @return dept_id字段，如果未找到返回null
     */
    private Field findDeptIdField(Class<?> clazz)
    {
        // 首先尝试查找deptId字段（驼峰命名）
        try
        {
            return clazz.getDeclaredField("deptId");
        }
        catch (NoSuchFieldException e)
        {
            // 如果没有找到，尝试查找dept_id字段（下划线命名）
            try
            {
                return clazz.getDeclaredField("dept_id");
            }
            catch (NoSuchFieldException ex)
            {
                // 如果当前类没有找到，递归查找父类
                Class<?> superClass = clazz.getSuperclass();
                if (superClass != null && superClass != Object.class)
                {
                    return findDeptIdField(superClass);
                }
                return null;
            }
        }
    }

    /**
     * 验证服务周期与合同的部门一致性
     * 
     * @param contractId 合同ID
     * @param servicePeriodId 服务周期ID（可选，用于更新时验证）
     */
    public void validateServicePeriodContractConsistency(Long contractId, Long servicePeriodId)
    {
        if (contractId == null)
        {
            return;
        }

        if (servicePeriodId != null)
        {
            validateRelatedDataConsistency("dc_contract", contractId, "dc_service_period", servicePeriodId);
        }
    }

    /**
     * 验证员工与服务周期的部门一致性
     * 
     * @param employeeId 员工ID
     * @param servicePeriodId 服务周期ID
     */
    public void validateEmployeeServicePeriodConsistency(Long employeeId, Long servicePeriodId)
    {
        if (employeeId == null || servicePeriodId == null)
        {
            return;
        }

        validateRelatedDataConsistency("dc_employee_info", employeeId, "dc_service_period", servicePeriodId);
    }

    /**
     * 验证债权与合同的部门一致性
     * 
     * @param contractId 合同ID
     * @param creditId 债权ID（可选，用于更新时验证）
     */
    public void validateCreditContractConsistency(Long contractId, Long creditId)
    {
        if (contractId == null)
        {
            return;
        }

        if (creditId != null)
        {
            validateRelatedDataConsistency("dc_contract", contractId, "dc_credit", creditId);
        }
    }

    /**
     * 验证融资申请与债权的部门一致性
     * 
     * @param creditId 债权ID
     * @param financingId 融资申请ID（可选，用于更新时验证）
     */
    public void validateFinancingCreditConsistency(Long creditId, Long financingId)
    {
        if (creditId == null)
        {
            return;
        }

        if (financingId != null)
        {
            validateRelatedDataConsistency("dc_credit", creditId, "dc_financing", financingId);
        }
    }
}