package com.hepl.tunefortwo.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

import com.hepl.tunefortwo.config.i18n.Translator;
import com.hepl.tunefortwo.config.security.JWTHelper;
import com.hepl.tunefortwo.dto.GenericResponse;
import com.hepl.tunefortwo.dto.ResetPasswordDto;
import com.hepl.tunefortwo.dto.UserDTO;
import com.hepl.tunefortwo.entity.FileType;
import com.hepl.tunefortwo.entity.Users;
import com.hepl.tunefortwo.service.FileService;
import com.hepl.tunefortwo.service.UserService;
import com.hepl.tunefortwo.utils.AppMessages;

import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.mail.MessagingException;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;

@Tag(name = "Create and Manage users", description = "")
@SecurityRequirement(name = "Bearer Authentication")
@RestController
@RequestMapping("/v1/users")
@Slf4j
public class UserController {

    private final JWTHelper jwtHelper;
    private final Translator translator;
    private final FileService fileService;
    private final UserService userService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    public UserController(JWTHelper jwtHelper, Translator translator, FileService fileService,
            UserService userService
            ,BCryptPasswordEncoder bCryptPasswordEncoder
            ) {
        this.jwtHelper = jwtHelper;
        this.translator = translator;
        this.fileService = fileService;
        this.userService = userService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    @PostMapping(consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
    public GenericResponse addUser(@ModelAttribute UserDTO userRequest)
            throws MessagingException, IOException {
        log.info("Adding Users for meeting agenda");
        // User JWT Helper to get information about user details.

        //Users user = jwtHelper.getUserDetail(authentication);
        if (userRequest.getProfilePhoto() != null) {
            fileService.uploadFile(userRequest.getProfilePhoto(), FileType.PROFILE);
        }
        userRequest.setPassword(bCryptPasswordEncoder.encode(userRequest.getPassword()));
        userService.saveUser(userRequest);

        GenericResponse response = new GenericResponse(true);
        response.setMessage(translator.toLocale(AppMessages.USER_SAVED));
        return response;
    }

    @GetMapping("/profile-pic/{filename}")
    public ResponseEntity<byte[]> serveFile(@PathVariable("filename") String filename) throws IOException {
        log.info("Get filename .. {}", filename);
        Resource file = fileService.loadAsResource(filename, FileType.PROFILE);

        if (file == null)
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, AppMessages.FILE_NOT_FOUND);

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
                .body(file.getContentAsByteArray());
    }
    
    @PostMapping("/forgot-password")
    public ResponseEntity<?> forgotPassword(@RequestParam("email") String email) throws MessagingException {
        Users user = userService.findUserForEmail(email);
        if (user == null) {
            
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body("User with email " + email + " not found.");
        }

        String resetToken = userService.generateResetToken();
        Users forgotUser = userService.setResetToken(user, resetToken);
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("email", forgotUser.getEmail());
        responseData.put("userName", forgotUser.getUsername());
        responseData.put("token", forgotUser.getResetToken());
        return ResponseEntity.ok(responseData);
    }
    
    @GetMapping("/reset-password")
    public ResponseEntity<?> showResetPasswordForm(@RequestParam("token") String token) {
        Users user = userService.findUserByToken(token);
        if (user == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body("Access Denied");
        }
        if (userService.isResetTokenExpired(user)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body("Please Try Password Reset Request again !!!");
        }
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("email", user.getEmail());
        
        return ResponseEntity.ok(responseData);
    }

    
    @PostMapping(value="/reset-password",consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
    public ResponseEntity<?> resetPassword(@ModelAttribute ResetPasswordDto passwordData) {
    	Users userForToken = new Users();
    	userForToken.setEmail(passwordData.getEmail());
    	 if (userService.isResetTokenExpired(userForToken)) {
    		 return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                     .body("Please Try Password Reset Request again !!!");

    	 }
    	 
    	 passwordData.setNewPassword(bCryptPasswordEncoder.encode(passwordData.getNewPassword()));
        
        return userService.updateNewPassword(passwordData);
    }

        


}
