package com.sn.sowsysrestapi.api.controller;

import com.sn.sowsysrestapi.api.converter.ReportConverter;
import com.sn.sowsysrestapi.api.dto.ReportDTO;
import com.sn.sowsysrestapi.api.dto.input.ReportInputDTO;
import com.sn.sowsysrestapi.api.dto.input.ReportUpdateInputDTO;
import com.sn.sowsysrestapi.api.dto.reportView.ReportBasicInfoWithWorkedHoursDTO;
import com.sn.sowsysrestapi.api.dto.reportView.ReportViewDTO;
import com.sn.sowsysrestapi.domain.entity.Report;
import com.sn.sowsysrestapi.domain.entity.ReportDirectory;
import com.sn.sowsysrestapi.domain.exception.BusinessException;
import com.sn.sowsysrestapi.domain.exception.ReportNotFoundException;
import com.sn.sowsysrestapi.domain.repository.ReportRepo;
import com.sn.sowsysrestapi.domain.service.ReportDirectoryService;
import com.sn.sowsysrestapi.domain.service.ReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.time.LocalDate;
import java.util.List;

@RestController
@RequestMapping("/api/reports")
public class ReportController {

    // Autowiring JdbcTemplate so we can send queries to the database
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    private ReportRepo reportRepo;
    @Autowired
    private ReportService reportService;

    @Autowired
    private ReportDirectoryService reportDirectoryService;

    @Autowired
    private ReportConverter reportConverter;

    @GetMapping
    public List<ReportBasicInfoWithWorkedHoursDTO> list(@RequestParam String userCode) {

        ReportDirectory reportDirectory = reportDirectoryService.findOrFailByOwnerCode(userCode);
        Long reportDirectoryId = reportDirectory.getId();

        return reportConverter.toCollectionWithReportBasicInfoDTO(
                reportRepo.findByReportDirectoryId(reportDirectoryId));

    }

    @GetMapping("/list-reports-info")
    public List<ReportBasicInfoWithWorkedHoursDTO> listBasicInfo() {

        return reportConverter.toCollectionWithReportBasicInfoDTO(reportRepo.findAll());
    }

    @GetMapping("/list-reports-by-period")
    public List<ReportViewDTO> listBasicInfo(
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {

        return reportConverter.toCollectionBasicInfoDTO(reportRepo.findByStartDateAndEndDate(startDate, endDate));
    }

    @GetMapping("/{id}")
    public ReportDTO find(@PathVariable Long id) {

        Report report = reportService.findOrFail(id);

        ReportDTO reportDTO = reportConverter.toDto(report);

        return reportDTO;
    }

    @GetMapping("/{id}/get-basic-info")
    public ReportBasicInfoWithWorkedHoursDTO getBasicReportInfo(@PathVariable Long id) {

        Report report = reportService.findOrFail(id);

        return reportConverter.toBasicInfoWithWorkedHoursDTO(report);
    }

    @GetMapping("/{reportId}/total-hours-completed-tasks")
    public Double getTotalWorkedHoursCompletedTasks(@PathVariable Long reportId) {

        return reportService.calculateTotalHoursSpentCompletedTasks(reportId);

    }

    @GetMapping("/{reportId}/total-hours-current-tasks")
    public Double getTotalWorkedHoursCurrentTasks(@PathVariable Long reportId) {

        return reportService.calculateTotalHoursSpentCurrentTasks(reportId);

    }

    @GetMapping("/{reportId}/total-hours-report")
    public Double getTotalWorkedHoursReport(@PathVariable Long reportId) {

        return reportService.calculateTotalWorkedHoursForTheReport(reportId);

    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public ReportDTO add(@RequestBody @Valid ReportInputDTO reportInputDTO) {

        try {
            Report report = reportConverter.toEntity(reportInputDTO);

            return reportConverter.toDto(reportService.save(report));
        } catch (ReportNotFoundException e) {
            throw new BusinessException(e.getMessage());
        }
    }

    @PutMapping("/{id}")
    public ReportDTO update(@PathVariable Long id, @RequestBody @Valid ReportUpdateInputDTO reportUpdateInputDTO) {

        try {
            Report reportPresent = reportService.findOrFail(id);

            reportConverter.copyToEntityToUpdate(reportUpdateInputDTO, reportPresent);

            return reportConverter.toDto(reportService.save(reportPresent));
        } catch (ReportNotFoundException e) {
            throw new BusinessException(e.getMessage());
        }

    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable Long id) {

        reportService.delete(id);
    }


}
