package com.ikon.projectmanagement.service.impl;

import java.util.List;
import java.util.NoSuchElementException;
import java.util.UUID;

import com.ikon.projectmanagement.dto.request.ProjectRequestDto;
import com.ikon.projectmanagement.dto.response.ProjectResponseDto;
import com.ikon.projectmanagement.dto.response.ProjectTimelineResponseDto;
import com.ikon.projectmanagement.entity.ProductOfProject;
import com.ikon.projectmanagement.entity.Project;
import com.ikon.projectmanagement.mapper.ProjectMapper;
import com.ikon.projectmanagement.repository.ProductOfProjectRepository;
import com.ikon.projectmanagement.repository.ProjectRepository;
import com.ikon.projectmanagement.service.ProjectService;
import com.ikon.webservice.WebService;

import java.time.LocalDate;
import java.time.LocalDateTime;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.apache.kafka.common.errors.ResourceNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Slf4j
public class ProjectServiceImpl extends WebService implements ProjectService {

    private final ProjectRepository projectRepository;
    private final ProductOfProjectRepository productOfProjectRepository;
    private final ProjectMapper projectMapper;

    // private final IkonServiceClient ikonServiceClient;

    @Override
    @Transactional
    public ProjectResponseDto createProject(ProjectRequestDto projectDto) {

        Project project = projectMapper.toEntity(projectDto);

        UUID accountId = getActiveAccountId();
        UUID createdById = getCurrentUserId();

        String createdAt = LocalDateTime.now().toString();

        project.setAccountId(accountId);
        project.setProjectStatus("Ongoing");

        Project savedProject = projectRepository.save(project);

        ProductOfProject product = new ProductOfProject();
        product.setAccountId(accountId);
        product.setCreatedBy(createdById);
        product.setCreatedOn(createdAt);
        product.setProductType(projectDto.getProductType());
        product.setProductStatus("Product Created");

        product.setProjectIdentifier(savedProject.getProjectIdentifier());
        product.setProjectName(savedProject.getProjectName());
        product.setProjectManager(savedProject.getProjectManager());

        ProductOfProject savedProduct = productOfProjectRepository.save(product);

        savedProject.setProduct(savedProduct);
        projectRepository.save(savedProject);

        return projectMapper.toResponse(savedProject);
    }

    @Override
    public List<ProjectResponseDto> getAllProjects() {

        UUID activeAccountId = getActiveAccountId();

        List<Project> projectList = projectRepository.findByAccountId(activeAccountId);

        return projectList.stream()
                .map(projectMapper::toResponse)
                .toList();
    }

    @Override
    public ProjectResponseDto getProjectByProjectIdentifier(UUID projectIdentifier) {
        Project project = projectRepository
                .findByProjectIdentifier(projectIdentifier)
                .orElseThrow(() -> new NoSuchElementException(
                        "Project not found with identifier: " + projectIdentifier));

        return projectMapper.toResponse(project);
    }

    @Override
    @Transactional
    public ProjectResponseDto updateProject(UUID projectIdentifier, ProjectRequestDto projectDto) {

        Project existingProject = projectRepository.findById(projectIdentifier)
                .orElseThrow(() -> new ResourceNotFoundException(
                        "Project not found with id: " + projectIdentifier));

        projectMapper.updateEntityFromDto(projectDto, existingProject);

        existingProject.setUpdatedOn(LocalDate.now());
        existingProject.setUpdatedBy(projectDto.getUpdatedBy());

        Project updatedProject = projectRepository.save(existingProject);

        return projectMapper.toResponse(updatedProject);
    }

    @Override
    public List<ProjectTimelineResponseDto> getAllActiveProjectsTimeline() {
        // Projects are created with status "Ongoing" (see createProject), so the
        // active-timeline must query that value — "ACTIVE" never matched anything.
        List<Project> activeProjects = projectRepository
                .findByProjectStatusIgnoreCase("Ongoing");

        return activeProjects.stream()
                .map(project -> ProjectTimelineResponseDto.builder()
                        .projectIdentifier(
                                project.getProjectIdentifier() != null
                                        ? project.getProjectIdentifier()
                                        : null)
                        .projectName(project.getProjectName())
                        .startDate(
                                project.getContractedStartDate() != null
                                        ? project.getContractedStartDate().toString()
                                        : null)
                        .endDate(
                                project.getContractedEndDate() != null
                                        ? project.getContractedEndDate().toString()
                                        : null)
                        .build())
                .toList();
    }
}