package com.ikon.projectmanagement.service.impl;

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

import com.ikon.projectmanagement.dto.request.IssueCreateRequestDto;
import com.ikon.projectmanagement.dto.response.IssueResponseDto;
import com.ikon.projectmanagement.entity.Issue;
import com.ikon.projectmanagement.mapper.IssueMapper;
import com.ikon.projectmanagement.repository.IssueRepository;
import com.ikon.projectmanagement.repository.ProjectRepository;
import com.ikon.projectmanagement.service.IssueService;
import com.ikon.webservice.WebService;

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 IssueServiceImpl extends WebService implements IssueService {

    private final IssueRepository issueRepository;
    private final ProjectRepository projectRepository;
    private final IssueMapper issueMapper;

    @Override
    @Transactional
    public IssueResponseDto createIssue(IssueCreateRequestDto issueCreateRequestDto) {

        log.info("Creating issue for project: {}", issueCreateRequestDto.getProjectIdentifier());

        UUID projectId = issueCreateRequestDto.getProjectIdentifier();

        projectRepository.findByProjectIdentifier(projectId)
                .orElseThrow(() -> new NoSuchElementException(
                        "Project not found with identifier: " + issueCreateRequestDto.getProjectIdentifier()));

        Issue issue = issueMapper.toEntity(issueCreateRequestDto);
        issue.setProjectIdentifier(projectId);
        issue.setIssueStatus("Active");

        Issue savedIssue = issueRepository.save(issue);

        return issueMapper.toResponse(savedIssue);
    }

    @Override
    public List<IssueResponseDto> getAllIssues(UUID projectIdentifier) {

        log.info("Fetching all issues");

        return issueRepository.findByProjectIdentifier(projectIdentifier)
                .stream()
                .map(issueMapper::toResponse)
                .toList();
    }

    @Override
    public IssueResponseDto getIssueById(UUID issueIdentifier) {

        log.info("Fetching issue with identifier: {}", issueIdentifier);

        Issue issue = issueRepository.findById(issueIdentifier)
                .orElseThrow(() -> new NoSuchElementException(
                        "Issue not found with identifier: " + issueIdentifier));

        return issueMapper.toResponse(issue);
    }

    @Override
    @Transactional
    public IssueResponseDto updateIssue(UUID issueIdentifier, IssueCreateRequestDto issueCreateRequestDto) {

        log.info("Updating issue with identifier: {}", issueIdentifier);

        Issue existingIssue = issueRepository.findById(issueIdentifier)
                .orElseThrow(() -> new ResourceNotFoundException(
                        "Issue not found with identifier: " + issueIdentifier));

        issueMapper.updateEntityFromDto(issueCreateRequestDto, existingIssue);

        Issue updatedIssue = issueRepository.save(existingIssue);

        log.info("Issue updated successfully with identifier: {}", issueIdentifier);

        return issueMapper.toResponse(updatedIssue);
    }

    @Override
    public List<IssueResponseDto> getIssuesByProject(String projectIdentifier) {

        log.info("Fetching all issues for project: {}", projectIdentifier);

        UUID projectId = UUID.fromString(projectIdentifier);

        // Validate project exists
        projectRepository.findByProjectIdentifier(projectId)
                .orElseThrow(() -> new NoSuchElementException(
                        "Project not found with identifier: " + projectIdentifier));

        return issueRepository.findByProjectIdentifier(projectId)
                .stream()
                .map(issueMapper::toResponse)
                .toList();
    }
}