package com.dne.ems.controller;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.dne.ems.dto.GridCoverageDTO;
import com.dne.ems.dto.GridUpdateRequest;
import com.dne.ems.model.Grid;
import com.dne.ems.model.UserAccount;
import com.dne.ems.model.enums.Role;
import com.dne.ems.repository.GridRepository;
import com.dne.ems.repository.UserAccountRepository;
import com.dne.ems.service.GridService;
import com.dne.ems.service.OperationLogService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

/**
 * 网格管理控制器，负责网格数据的查询、更新和网格员分配管理
 *
 * <p>主要功能包括：
 * <ul>
 *   <li>网格数据查询与分页</li>
 *   <li>网格信息更新</li>
 *   <li>网格员分配与解除分配</li>
 *   <li>网格覆盖率统计</li>
 * </ul>
 *
 * @author DNE开发团队
 * @version 1.0
 * @since 2024
 */
@RestController
@RequestMapping("/api/grids")
@RequiredArgsConstructor
public class GridController {

    private final GridService gridService;
    private final GridRepository gridRepository;
    private final UserAccountRepository userAccountRepository;
    private final OperationLogService operationLogService;
    
    // 添加日志记录器
    private static final Logger logger = LoggerFactory.getLogger(GridController.class);

    /**
     * 获取网格列表(可分页和过滤)
     *
     * @return 符合条件的网格分页列表
     * @see Grid
     */
    @GetMapping
    @PreAuthorize("hasRole('ADMIN') or hasRole('DECISION_MAKER') or hasRole('GRID_WORKER')")
    public ResponseEntity<List<Grid>> getGrids() {
        List<Grid> grids = gridRepository.findAll();
        return ResponseEntity.ok(grids);
    }

    /**
     * 更新网格信息
     *
     * @param id 要更新的网格ID
     * @param request 包含更新数据的请求体
     * @return 更新后的网格实体
     * @throws ResourceNotFoundException 如果网格不存在
     * @see GridUpdateRequest
     */
    @Operation(summary = "Update a grid by ID")
    @PatchMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Grid> updateGrid(
        @Parameter(description = "Grid ID") @PathVariable Long id,
        @Valid @RequestBody GridUpdateRequest request
    ) {
        Grid updatedGrid = gridService.updateGrid(id, request);
        return ResponseEntity.ok(updatedGrid);
    }

    /**
     * 获取网格覆盖率统计数据
     *
     * @return 各城市网格覆盖率数据列表
     * @see GridCoverageDTO
     */
    @GetMapping("/coverage")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<List<GridCoverageDTO>> getGridCoverage() {
        List<GridCoverageDTO> coverage = gridRepository.getGridCoverageByCity();
        return ResponseEntity.ok(coverage);
    }

    /**
     * 分配网格员到指定网格
     *
     * @param gridId 目标网格ID
     * @param request 包含用户ID的请求体
     * @return 操作结果
     * @throws ResourceNotFoundException 如果网格或用户不存在
     * @throws IllegalArgumentException 如果用户不是网格员角色
     */
    @PostMapping("/{gridId}/assign")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> assignGridWorker(
            @PathVariable Long gridId,
            @RequestBody Map<String, Long> request) {
        Long userId = request.get("userId");
        if (userId == null) {
            return ResponseEntity.badRequest().body("用户ID不能为空");
        }
        
        Optional<Grid> gridOpt = gridRepository.findById(gridId);
        Optional<UserAccount> userOpt = userAccountRepository.findById(userId);
        
        if (gridOpt.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        
        if (userOpt.isEmpty()) {
            return ResponseEntity.badRequest().body("用户不存在");
        }
        
        Grid grid = gridOpt.get();
        UserAccount user = userOpt.get();
        
        if (user.getRole() != Role.GRID_WORKER) {
            return ResponseEntity.badRequest().body("只能分配网格员角色的用户");
        }
        
        user.setGridX(grid.getGridX());
        user.setGridY(grid.getGridY());
        userAccountRepository.save(user);
        
        // 记录操作日志
        operationLogService.recordOperation(
            com.dne.ems.model.enums.OperationType.UPDATE,
            "将网格员 " + user.getName() + " (ID: " + userId + ") 分配到网格 (ID: " + gridId + ")",
            userId.toString(),
            "UserAccount"
        );
        
        return ResponseEntity.ok().build();
    }

    /**
     * 从网格中移除网格员
     *
     * @param gridId 目标网格ID
     * @return 操作结果
     * @throws ResourceNotFoundException 如果网格不存在
     */
    @PostMapping("/{gridId}/unassign")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> removeGridWorker(@PathVariable Long gridId) {
        Optional<Grid> gridOpt = gridRepository.findById(gridId);
        
        if (gridOpt.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        
        Grid grid = gridOpt.get();
        
        // 使用新添加的方法查找指定网格坐标的网格员
        List<UserAccount> workers = userAccountRepository.findGridWorkersByCoordinates(
            grid.getGridX(), grid.getGridY());
        
        for (UserAccount worker : workers) {
            worker.setGridX(-1);
            worker.setGridY(-1);
            userAccountRepository.save(worker);
        }
        
        return ResponseEntity.ok().build();
    }

    /**
     * 通过网格坐标分配网格员，仅限ADMIN角色使用。
     *
     * @param gridX 网格X坐标
     * @param gridY 网格Y坐标
     * @param request 包含用户ID的请求体
     * @return 操作结果响应
     */
    @PostMapping("/coordinates/{gridX}/{gridY}/assign")
    @PreAuthorize("hasAnyRole('ADMIN', 'GRID_WORKER')")
    public ResponseEntity<?> assignGridWorkerByCoordinates(
            @PathVariable Integer gridX,
            @PathVariable Integer gridY,
            @RequestBody Map<String, Long> request) {
        logger.info("开始通过坐标分配网格员: gridX={}, gridY={}, request={}", gridX, gridY, request);
        
        Long userId = request.get("userId");
        if (userId == null) {
            logger.warn("分配网格员失败: 用户ID为空");
            return ResponseEntity.badRequest().body("用户ID不能为空");
        }

        try {
            // 通过坐标查找网格
            logger.debug("查询网格坐标: gridX={}, gridY={}", gridX, gridY);
            Optional<Grid> gridOpt = gridRepository.findByGridXAndGridY(gridX, gridY);
            
            if (gridOpt.isEmpty()) {
                logger.warn("分配网格员失败: 未找到网格, gridX={}, gridY={}", gridX, gridY);
                
                // 尝试查询所有网格，看看是否有数据
                List<Grid> allGrids = gridRepository.findAll();
                logger.debug("数据库中共有 {} 个网格", allGrids.size());
                if (!allGrids.isEmpty()) {
                    Grid firstGrid = allGrids.get(0);
                    logger.debug("第一个网格: id={}, gridX={}, gridY={}, cityName={}", 
                        firstGrid.getId(), firstGrid.getGridX(), firstGrid.getGridY(), firstGrid.getCityName());
                }
                
                return ResponseEntity.status(404).body("未找到指定坐标的网格");
            }
            
            logger.debug("查询用户: userId={}", userId);
            Optional<UserAccount> userOpt = userAccountRepository.findById(userId);

            if (userOpt.isEmpty()) {
                logger.warn("分配网格员失败: 未找到用户, userId={}", userId);
                return ResponseEntity.badRequest().body("用户不存在");
            }

            Grid grid = gridOpt.get();
            UserAccount user = userOpt.get();
            
            logger.debug("网格信息: id={}, gridX={}, gridY={}", grid.getId(), grid.getGridX(), grid.getGridY());
            logger.debug("用户信息: id={}, name={}, role={}", user.getId(), user.getName(), user.getRole());

            if (user.getRole() != Role.GRID_WORKER) {
                logger.warn("分配网格员失败: 用户角色不是网格员, userId={}, role={}", userId, user.getRole());
                return ResponseEntity.badRequest().body("只能分配网格员角色的用户");
            }

            // 先检查是否有其他网格员已分配到此网格
            logger.debug("检查是否有其他网格员已分配到此网格: gridX={}, gridY={}", gridX, gridY);
            List<UserAccount> existingWorkers = userAccountRepository.findGridWorkersByCoordinates(gridX, gridY);
            logger.debug("已分配的网格员数量: {}", existingWorkers.size());
            
            for (UserAccount existingWorker : existingWorkers) {
                if (!existingWorker.getId().equals(userId)) {
                    logger.info("移除已存在的网格员: workerId={}, name={}", existingWorker.getId(), existingWorker.getName());
                    existingWorker.setGridX(-1);
                    existingWorker.setGridY(-1);
                    userAccountRepository.save(existingWorker);
                }
            }

            // 分配新网格员
            logger.info("分配网格员: userId={}, name={}, gridX={}, gridY={}", user.getId(), user.getName(), grid.getGridX(), grid.getGridY());
            user.setGridX(grid.getGridX());
            user.setGridY(grid.getGridY());
            userAccountRepository.save(user);
            
            // 记录操作日志
            operationLogService.recordOperation(
                com.dne.ems.model.enums.OperationType.UPDATE,
                "将网格员 " + user.getName() + " (ID: " + userId + ") 分配到网格 (X: " + gridX + ", Y: " + gridY + ")",
                userId.toString(),
                "UserAccount"
            );

            logger.info("成功将用户 {} 分配到网格 (X: {}, Y: {})", user.getName(), gridX, gridY);
            return ResponseEntity.ok().build();
            
        } catch (Exception e) {
            logger.error("通过坐标分配网格员时发生异常", e);
            return ResponseEntity.status(500).body("服务器内部错误");
        }
    }

    /**
     * 通过网格坐标移除网格员，仅限ADMIN角色使用。
     *
     * @param gridX 网格X坐标
     * @param gridY 网格Y坐标
     * @return 操作结果响应
     */
    @PostMapping("/coordinates/{gridX}/{gridY}/unassign")
    @PreAuthorize("hasAnyRole('ADMIN', 'GRID_WORKER')")
    public ResponseEntity<?> removeGridWorkerByCoordinates(
            @PathVariable Integer gridX,
            @PathVariable Integer gridY) {
        logger.info("开始通过坐标移除网格员: gridX={}, gridY={}", gridX, gridY);
        
        try {
            // 查找指定坐标的网格员
            logger.debug("查询指定坐标的网格员: gridX={}, gridY={}", gridX, gridY);
            List<UserAccount> workers = userAccountRepository.findGridWorkersByCoordinates(gridX, gridY);
            logger.debug("找到网格员数量: {}", workers.size());

            if (workers.isEmpty()) {
                logger.warn("移除网格员失败: 未找到网格员, gridX={}, gridY={}", gridX, gridY);
                return ResponseEntity.status(404).body("未找到指定坐标的网格员");
            }

            // 移除所有网格员的分配
            for (UserAccount worker : workers) {
                logger.info("移除网格员分配: workerId={}, name={}, 原坐标: gridX={}, gridY={}", 
                        worker.getId(), worker.getName(), worker.getGridX(), worker.getGridY());
                
                try {
                    worker.setGridX(-1);
                    worker.setGridY(-1);
                    UserAccount savedWorker = userAccountRepository.save(worker);
                    logger.info("网格员移除成功: workerId={}, 新坐标: gridX={}, gridY={}", 
                            savedWorker.getId(), savedWorker.getGridX(), savedWorker.getGridY());
                    
                    // 验证保存是否成功
                    UserAccount verifiedWorker = userAccountRepository.findById(worker.getId()).orElse(null);
                    if (verifiedWorker != null) {
                        logger.debug("验证移除结果: gridX={}, gridY={}", verifiedWorker.getGridX(), verifiedWorker.getGridY());
                    }
                } catch (Exception e) {
                    logger.error("保存用户数据时发生异常", e);
                    return ResponseEntity.status(500).body("保存用户数据失败: " + e.getMessage());
                }
            }

            return ResponseEntity.ok().build();
        } catch (Exception e) {
            logger.error("移除网格员时发生异常", e);
            return ResponseEntity.status(500).body("移除网格员失败: " + e.getMessage());
        }
    }
} 