package studycave.studycaverestservice.controller;


import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import io.swagger.annotations.Api;
import studycave.studycaverestservice.model.badge.Badge;
import studycave.studycaverestservice.model.badge.BadgeRepository;
import studycave.studycaverestservice.model.flashcard.FlashcardRepository;
import studycave.studycaverestservice.model.flashcardset.SetRepository;
import studycave.studycaverestservice.model.material.Material;
import studycave.studycaverestservice.model.material.MaterialRepository;
import studycave.studycaverestservice.model.material.dto.MaterialGetDTO;
import studycave.studycaverestservice.model.storage.StorageService;
import studycave.studycaverestservice.model.studyGroup.GroupRepository;
import studycave.studycaverestservice.model.user.User;
import studycave.studycaverestservice.model.user.UserRepository;
import studycave.studycaverestservice.model.userBadge.UserBadge;
import studycave.studycaverestservice.model.userBadge.UserBadgeRepository;

@RestController
@CrossOrigin
@RequestMapping("/file")
@Api
public class UploadController {

    @Autowired
    StorageService storageService;
    @Autowired
    FlashcardRepository flashcardRepository;
    @Autowired
    SetRepository setRepository;
    @Autowired
    ModelMapper modelMapper;
    @Autowired
    MaterialRepository materialRepository;
    @Autowired
    UserRepository userRepository;
    @Autowired
    GroupRepository groupRepository;
    @Autowired
    UserBadgeRepository userBadgeRepository;
    @Autowired
    BadgeRepository badgeRepository;
    /*@Autowired
    S3ServicesImpl amazonFolder;
    @Autowired
    private AmazonS3 s3client;

    private String bucketName = "studycave-folder";
*/
    List<String> files = new ArrayList<String>();


    @PostMapping("/save")//----------------------------------------------- file save
    public ResponseEntity<String> handleFileSave(@RequestParam String owner,@RequestParam String permission,@RequestParam String title,@RequestParam int grade, @RequestParam("file") MultipartFile file){
        String msg ="";
        try {
            DateFormat currentDate = new SimpleDateFormat("MM.dd.yyyy.HH.mm.ss");
            Date today = Calendar.getInstance().getTime();
            storageService.save(file);
            File convFile = new File(System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") +file.getOriginalFilename());
            file.transferTo(convFile);
            //s3client.putObject(new PutObjectRequest(bucketName,currentDate.format(today) + file.getOriginalFilename() , convFile).withCannedAcl(CannedAccessControlList.PublicRead));

            String filepath = "save-dir\\" + file.getOriginalFilename();

            files.add(file.getOriginalFilename());
            Material material = new Material();



            java.util.Date utilDate = new java.util.Date();
            java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());

            material.setPermission(permission);
            material.setTitle(title);
            material.setAddDate(sqlDate);
            material.setEditDate(sqlDate);
            material.setGrade(grade);
            User user = userRepository.findByUsername(owner).get();
            material.setOwner(Math.toIntExact(user.getId()));

            File newfile = new File(filepath);
            String newfilepath = "save-dir\\" + currentDate.format(today) + file.getOriginalFilename();
            newfilepath = newfilepath.replaceAll("\\s","");
            File newfilename = new File(newfilepath);
            newfile.renameTo(newfilename);
            String simplepath = currentDate.format(today) + file.getOriginalFilename();
            material.setPath(simplepath);
            materialRepository.save(material);
            //amazonFolder.uploadFile(material.getPath(),"save-dir\\" + material.getPath());
            msg = "You successfully uploaded " + file.getOriginalFilename() + "!";
            if(userBadgeRepository.findByIdAndUser((long)6, user.getId()).isEmpty()) {
                UserBadge badgeAchieved = new UserBadge();
                Badge badge = new Badge();
                badge = badgeRepository.findById((long)6).orElse(null);
                badgeAchieved.setBadge(badge);
                badgeAchieved.setUser(user);
                userBadgeRepository.save(badgeAchieved);
            }
            return ResponseEntity.status(HttpStatus.OK).body(msg);
        }catch(Exception e) {
            e.printStackTrace();
            msg = "FAIL to upload " + file.getOriginalFilename() + "!";
            return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(msg);
        }
    }

    @GetMapping("/materials")
    public ResponseEntity<?> getMaterials(
            @RequestParam(value = "owner", required = false) String  owner,
            @RequestParam(value = "permission", required = false) String permission) {

        System.out.println("Owner: " + owner);
        Optional<User> user = userRepository.findByUsername(owner);
        Integer ownerId = user.isPresent() ? user.get().getId().intValue() : null;

        System.out.println("Owner ID: " + ownerId);
        if (owner!=null && !user.isPresent()) return new ResponseEntity<>(new String("User not found"),HttpStatus.NOT_FOUND);

        System.out.println("Permission: " + permission);
        List<MaterialGetDTO> materialDTOs = new ArrayList<>();
        List<Material> materials = materialRepository.findByOptionalPermissionAndOptionalOwnerAndGroupIdNull(permission,ownerId);

        for(Material material : materials) {
            System.out.println(material);
            String username = userRepository.findById((long) material.getOwner()).get().getUsername();
            System.out.println("Username: " + username);
            MaterialGetDTO materialDTO = new MaterialGetDTO();
            materialDTO.setAddDate(material.getAddDate());
            materialDTO.setEditDate(material.getEditDate());
            materialDTO.setGrade(material.getGrade());
            materialDTO.setId(material.getId());
            materialDTO.setTitle(material.getTitle());
            materialDTO.setPermission(material.getPermission());
            materialDTO.setOwner(username);
            if(material.getGroup() != null )
                if((long)material.getGroup().getId() != 0 )
                    materialDTO.setGroup(groupRepository.findById(material.getGroup().getId()).orElse(null).getName());
            materialDTOs.add(materialDTO);
        }
        return new ResponseEntity<List<MaterialGetDTO>>(materialDTOs, HttpStatus.OK);
    }

    @PutMapping("materials/{id}/permission")
    public void changePermission(@PathVariable(required = true) Long id, @RequestBody String permission) {
        Material material = materialRepository.findById(id).get();
        material.setPermission(permission);
        materialRepository.save(material);
    }

    @GetMapping("materials/{id}/permission")
    public ResponseEntity<String> getPermission(@PathVariable(required = true) Long id) throws IOException {
        Material material = materialRepository.findById(id).get();

        return ResponseEntity.status(HttpStatus.OK).body(material.getPermission());
        //return material.getPermission();
    }

    @DeleteMapping("/delete/{id}")
    public ResponseEntity<String> deletematerial(@PathVariable(required = true)Long id) {

        //Authorization
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String currentPrincipalName = authentication.getName();
        Long userId = userRepository.findByUsername(currentPrincipalName).get().getId();

        System.out.println();

        if (!userId.equals((long)materialRepository.findById(id).get().getOwner())) {
            return new ResponseEntity("Access Forbidden", HttpStatus.FORBIDDEN);
        }
        //

        // storageService.savedelete((materialRepository.findById(id).orElse(null)).getPath());
        materialRepository.deleteById(id);
        return ResponseEntity.status(HttpStatus.OK).body("usunieto");
    }

    @GetMapping("/files/{id}")
    @ResponseBody
    public ResponseEntity<Resource> getFile(@PathVariable(required = true) Long id) {
        //Authorization
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String currentPrincipalName = authentication.getName();
        Long userId = userRepository.findByUsername(currentPrincipalName).orElse(null).getId();

        Material material = materialRepository.findById(id).orElse(null);
        ResourceLoader rl = new DefaultResourceLoader();
        Resource file = rl.getResource("url:https://s3-eu-west-1.amazonaws.com/studycave-folder/" + material.getPath());

        // ------------------------------------------------------------------------- LOCAL
//		Resource file = storageService.loadFile(material.getPath());

        if(userBadgeRepository.findByIdAndUser((long)11, userId).isEmpty()) {
            UserBadge badgeAchieved = new UserBadge();
            Badge badge = new Badge();
            badge = badgeRepository.findById((long)11).orElse(null);
            badgeAchieved.setBadge(badge);
            badgeAchieved.setUser(userRepository.findById(userId).orElse(null));
            userBadgeRepository.save(badgeAchieved);
        }
        return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
    }
}
