package com.dne.ems.service.impl;

// import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.dne.ems.dto.GridUpdateRequest;
import com.dne.ems.exception.ResourceNotFoundException;
import com.dne.ems.model.Grid;
import com.dne.ems.model.MapGrid;
import com.dne.ems.model.UserAccount;
import com.dne.ems.repository.GridRepository;
import com.dne.ems.repository.MapGridRepository;
import com.dne.ems.repository.UserAccountRepository;
import com.dne.ems.service.GridService;
import com.dne.ems.service.OperationLogService;

import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;

/**
 * 网格服务实现类，处理网格数据的查询和更新
 *
 * <p>实现了 {@link GridService} 接口定义的所有方法，包括：
 * <ul>
 *   <li>网格数据查询与过滤</li>
 *   <li>网格信息更新</li>
 * </ul>
 *
 * @author DNE开发团队
 * @version 1.0
 * @since 2025
 */
@Service
@RequiredArgsConstructor
public class GridServiceImpl implements GridService {

    private final GridRepository gridRepository;
    private final UserAccountRepository userAccountRepository;
    private final MapGridRepository mapGridRepository;
    private final OperationLogService operationLogService;

    /**
     * {@inheritDoc}
     *
     * <p>实现细节：
     * <ol>
     *   <li>使用Specification动态构建查询条件</li>
     *   <li>支持按城市和区县过滤</li>
     *   <li>返回分页结果</li>
     * </ol>
     *
     * @param cityName 城市名称过滤条件(可选)
     * @param districtName 区县名称过滤条件(可选)
     * @param pageable 分页参数
     * @return 网格分页列表
     */
    @Override
    public Page<Grid> getGrids(String cityName, String districtName, Pageable pageable) {
        List<Grid> allGrids = gridRepository.findAll();

        // In-memory filtering
        List<Grid> filteredGrids = allGrids.stream()
            .filter(grid -> !StringUtils.hasText(cityName) || cityName.equals(grid.getCityName()))
            .filter(grid -> !StringUtils.hasText(districtName) || districtName.equals(grid.getDistrictName()))
            .collect(Collectors.toList());

        // Manual pagination
        int start = (int) pageable.getOffset();
        int end = Math.min((start + pageable.getPageSize()), filteredGrids.size());
        
        List<Grid> pageContent = (start > filteredGrids.size()) ? List.of() : filteredGrids.subList(start, end);

        return new PageImpl<>(pageContent, pageable, filteredGrids.size());
    }

    @Override
    public List<Grid> getAllGrids() {
        return gridRepository.findAll();
    }

    @Override
    public Optional<Grid> getGridById(Long gridId) {
        return gridRepository.findById(gridId);
    }

    @Override
    @Transactional
    public UserAccount assignWorkerToGrid(Long gridId, Long userId) {
        Grid grid = gridRepository.findById(gridId)
                .orElseThrow(() -> new ResourceNotFoundException("Grid not found with id: " + gridId));
        UserAccount user = userAccountRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));

        // Unassign from any previous grid
        unassignWorkerFromAnyGrid(userId);
        
        user.setGridX(grid.getGridX());
        user.setGridY(grid.getGridY());
        return userAccountRepository.save(user);
    }

    @Override
    @Transactional
    public void unassignWorkerFromGrid(Long gridId) {
        Grid grid = gridRepository.findById(gridId)
                .orElseThrow(() -> new ResourceNotFoundException("Grid not found with id: " + gridId));

        userAccountRepository.findByGridXAndGridY(grid.getGridX(), grid.getGridY()).ifPresent(user -> {
            user.setGridX(null);
            user.setGridY(null);
            userAccountRepository.save(user);
        });
    }

    private void unassignWorkerFromAnyGrid(Long userId) {
        UserAccount user = userAccountRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        if (user.getGridX() != null && user.getGridY() != null) {
            user.setGridX(null);
            user.setGridY(null);
            userAccountRepository.save(user);
        }
    }

    @Override
    @Transactional
    public Grid updateGrid(Long gridId, GridUpdateRequest request) {
        Grid grid = gridRepository.findById(gridId)
                .orElseThrow(() -> new EntityNotFoundException("Grid not found with id: " + gridId));

        // Sync obstacle status to MapGrid if it's being updated
        if (request.getIsObstacle() != null && !request.getIsObstacle().equals(grid.getIsObstacle())) {
            grid.setIsObstacle(request.getIsObstacle());
            
            MapGrid mapGrid = mapGridRepository.findByXAndY(grid.getGridX(), grid.getGridY())
                .orElseGet(() -> MapGrid.builder()
                                        .x(grid.getGridX())
                                        .y(grid.getGridY())
                                        .cityName(grid.getCityName())
                                        .build());
            
            mapGrid.setObstacle(request.getIsObstacle());
            mapGridRepository.save(mapGrid);
        }

        if (request.getDescription() != null) {
            grid.setDescription(request.getDescription());
        }

        Grid updatedGrid = gridRepository.save(grid);

        operationLogService.recordOperation(
            com.dne.ems.model.enums.OperationType.UPDATE,
            "更新了网格信息, 网格ID: " + gridId,
            gridId.toString(),
            "Grid"
        );

        return updatedGrid;
    }
} 