package io.gmss.fiscad.controllers.infocad.metier;

import io.gmss.fiscad.entities.infocad.metier.Upload;
import io.gmss.fiscad.paylaods.ApiResponse;
import io.gmss.fiscad.repositories.infocad.metier.UploadRepository;
import io.gmss.fiscad.service.FileStorageService;
import io.gmss.fiscad.service.StringManager;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;

/**
 * @author AKAKPO Aurince
 */
@RestController
@RequestMapping(value = "/api/upload", produces = MediaType.APPLICATION_JSON_VALUE)
@Data
@SecurityRequirement(name = "bearer")
@Tag(name = "Upload")
@CrossOrigin(origins = "*")
@PreAuthorize("hasRole('ADMIN') or hasRole('SUPERVISEUR') or hasRole('ENQUETEUR')")
public class UploadController {

    boolean headIsValid = false;

    private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
    @Autowired
    private UploadRepository uploadRepository;
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private StringManager stringManager;
    private int firstLineColumnNumber = 0;
    private String fileHeader;
    private String fileHeaderType;
    private int anneeFiscale;
    private int indiceOfFile = 0;


    private SimpleDateFormat sdf = new SimpleDateFormat("YYYYMMDD");
    private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYYMMDD");


    @GetMapping("/all")
    public ResponseEntity<?> all() {
        try {
            if (uploadRepository.findAll().isEmpty()) {
                return new ResponseEntity<>(new ApiResponse(true, uploadRepository.findAll(), "Empty list. No values present."), HttpStatus.OK);
            } else {
                return new ResponseEntity<>(new ApiResponse(true, uploadRepository.findAll(), "All uploads files founded."), HttpStatus.OK);
            }
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

    @GetMapping("/id/{id}")
    public ResponseEntity<?> one(@PathVariable Long id) {

        try {
            if (uploadRepository.findById(id).isPresent()) {
                return new ResponseEntity<>(new ApiResponse(true, uploadRepository.getOne(id), "File with id {" + id + "} is found."), HttpStatus.OK);
            } else {
                return new ResponseEntity<>(new ApiResponse(true, null, "The upload with id {" + id + "} you request for is not found."), HttpStatus.OK);
            }
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }


    /**
     * @param fileName
     * @param request
     * @return
     */
    @GetMapping("/downloadfile/{fileName:.+}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) {
        // Load file as Resource
        Resource resource = fileStorageService.loadFileAsResource(fileName);

        // Try to determine file's content type
        String contentType = null;
        try {
            contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
        } catch (IOException ex) {
            logger.info("Could not determine file type.");
        }

        // Fallback to the default content type if type could not be determined
        if (contentType == null) {
            contentType = "application/octet-stream";
        }

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(contentType))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }

    @PostMapping("/save")
    public ResponseEntity<?> save(@RequestPart(required = true) MultipartFile file, @RequestParam String reference, @RequestParam String description /*, @RequestParam Long idTypeUpload*/) {

        try {
            Upload upload = new Upload();
            String fileName = fileStorageService.storeFile(file);
            upload.setFileName(fileName);
            upload.setMimeType(file.getContentType());
            upload.setSize(file.getSize());
            upload.setOriginalFileName(file.getOriginalFilename());
            return new ResponseEntity<>(new ApiResponse(true, uploadRepository.save(upload), "File has been created successfully."), HttpStatus.OK);
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NullPointerException e) {
            e.printStackTrace();
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }


    @DeleteMapping("/delete/id/{id}")
    public ResponseEntity<?> delete(@PathVariable Long id) {
        try {
            if (id != null || uploadRepository.findById(id).isPresent()) {
                String name = uploadRepository.getOne(id).getFileName();
                fileStorageService.deleteFile(name);
                uploadRepository.deleteById(id);
                return new ResponseEntity<>(new ApiResponse(true, null, "File with name {" + name + "} has been deleted successfully."), HttpStatus.OK);
            } else {
                return new ResponseEntity<>(new ApiResponse(true, null, "The upload specified in your request body is not found."), HttpStatus.OK);
            }
        } catch (HttpClientErrorException.MethodNotAllowed e) {
            return new ResponseEntity<>(new ApiResponse(false, null, "Method POST/GET is required."), HttpStatus.OK);
        } catch (NullPointerException e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "Null value has been detected {" + e.getMessage() + "}."), HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
            return new ResponseEntity<>(new ApiResponse(false, null, "An error has been occur and the content is {" + e.getMessage() + "}."), HttpStatus.OK);
        }
    }

}
