package com.hepl.tunefortwo.controller;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.sound.sampled.UnsupportedAudioFileException;

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.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
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.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.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;

import com.hepl.tunefortwo.config.i18n.Translator;
import com.hepl.tunefortwo.dto.AccessControlStatus;
import com.hepl.tunefortwo.dto.GenericData;
import com.hepl.tunefortwo.dto.GenericResponse;
import com.hepl.tunefortwo.dto.InstrumentRequestDto;
import com.hepl.tunefortwo.entity.FileType;
import com.hepl.tunefortwo.service.AudioService;
import com.hepl.tunefortwo.service.FileService;
import com.hepl.tunefortwo.service.InstrumentService;
import com.hepl.tunefortwo.utils.AppMessages;
import com.hepl.tunefortwo.utils.JwtUtils;
import org.springframework.data.domain.Sort;

import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Operation;
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 Instrument", description = "")
//@SecurityRequirement(name = "Bearer Authentication")
@RestController
@RequestMapping("/v1/instrument")
@Slf4j
public class InstrumentController {
	private final Translator translator;
	private final InstrumentService instrumentService;
	private final FileService fileService;
	private final AudioService audioService;
	private final JwtUtils jwtUtils;

	public InstrumentController(Translator translator, InstrumentService instrumentService, FileService fileService, AudioService audioService,JwtUtils jwtUtils) {
		this.instrumentService = instrumentService;
		this.translator = translator;
		this.fileService = fileService;
		this.audioService = audioService;
		this.jwtUtils = jwtUtils;
	}

	

	@PostMapping(consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
	public GenericResponse addInstrument(@Validated @ModelAttribute InstrumentRequestDto data, Authentication authentication)
	        throws Exception {
	    boolean isAdmin = false;
	    if (authentication instanceof JwtAuthenticationToken) {
	        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
	        Jwt jwt = jwtAuthToken.getToken();
	        String tokenValue = jwt.getTokenValue();
	        Claims claims = jwtUtils.extractClaims(tokenValue);
	        String email = claims.getSubject();
	        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
	        if (userDetails != null) {
	            String roleId = (String) userDetails.get("roleId");
	            String userId = (String) userDetails.get("id");
	            if (roleId.equals("1")) {
	                isAdmin = true;
	            }
	        }
	    }

	    if (!isAdmin) {
	        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
	        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
	    }


	    if (data.getAudio() != null) {
	        String originalFilename = data.getAudio().getOriginalFilename();
	        if (originalFilename != null) {
	            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
	            List<String> allowedExtensions = Arrays.asList("mp3", "wav", "ogg", "aac"); // corrected case for extensions
	            if (!allowedExtensions.contains(fileExtension.toLowerCase())) {
	                throw new MessagingException("Only MP3, AAC, OGG, and WAV files are allowed");
	            }
	        }
	        data.setAudioPath(fileService.uploadFile(data.getAudio(), FileType.CLIP));

	        String filename = fileService.uploadFile(data.getAudio(), FileType.CLIP);
	        Resource file = fileService.loadAsResource(filename, FileType.CLIP);
	        Path filePath = Paths.get(file.getURI());
	        System.out.println("FilePath while posting---" + filePath);
	        double durationInSeconds = audioService.getAudioDuration(filePath.toFile());

	        long durationRound = (long) Math.floor(durationInSeconds);
	        long minutes = durationRound / 60;
	        long seconds = durationRound % 60;
	        String formattedTime = String.format("%02d:%02d", minutes, seconds);
	        data.setAudioDuration(formattedTime);
	    }

	    log.info("Adding Instrument");
	    instrumentService.saveInstrument(data);
	    GenericResponse response = new GenericResponse(true);
	    response.setMessage(translator.toLocale(AppMessages.INSTRUMENT_SAVED));
	    return response;
	}


//	@GetMapping()
//	public GenericResponse getAllInstrument() {
//		log.info("Get all Instruments");
//		GenericResponse response = new GenericResponse(true);
//		GenericData data = new GenericData();
//		data.setInstruments(instrumentService.getAllInstruments());
//		response.setData(data);
//		return response;
//	}
	@GetMapping()
	public GenericResponse getAllInstrumentSortedByPrice() {
	    log.info("Get all Instruments sorted by price in ascending order");
	    GenericResponse response = new GenericResponse(true);
	    GenericData data = new GenericData();
	    data.setInstruments(instrumentService.getAllInstrumentsSortedByPrice(Sort.Direction.ASC));
	    response.setData(data);
	    return response;
	}
	
	@GetMapping("/getallinsrumentimages")
	public GenericResponse getAllImagesForInstruments() {
	    log.info("Get all Instruments with Images and description");
	    GenericResponse response = new GenericResponse(true);
	    GenericData data = new GenericData();
	    data.setAllInstrumentImages(instrumentService.getAllImagesForInstruments());
	    response.setData(data);
	    return response;
	}
	
	@GetMapping("/get-AllInstrument-Active")
	public GenericResponse getAllInstrumentsByActive() {
		log.info("Get all Instruments");
		GenericResponse response = new GenericResponse(true);
		GenericData data = new GenericData();
		data.setInstruments(instrumentService.getAllInstrumentsByActive());
		response.setData(data);
		return response;
	}
	
	 @GetMapping("/{id}")
	    public GenericResponse getInstrumentById(@PathVariable String id, Authentication authentication) {
		 boolean isAdmin = false;
		    if (authentication instanceof JwtAuthenticationToken) {
		        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
		        Jwt jwt = jwtAuthToken.getToken();
		        String tokenValue = jwt.getTokenValue();
		        Claims claims = jwtUtils.extractClaims(tokenValue);
		        String email = claims.getSubject();
		        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
		        if (userDetails != null) {
		            String roleId = (String) userDetails.get("roleId");
		            String userId = (String) userDetails.get("id");
		            if (roleId.equals("1")) {
		                isAdmin = true;
		            }
		        }
		    }

		    if (!isAdmin) {
		        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
		        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
		    }
	        log.info("Get instrument");

	        GenericResponse response = new GenericResponse(true);
	        GenericData data = new GenericData();

	        data.setInstrument(instrumentService.getInstrumentById(id));
	        response.setData(data);
	        return response;
	    }

	@Operation(description = "Update Instrument based on id")
	@PutMapping(value="/{id}", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
	public GenericResponse updateInstrument(@PathVariable String id,
			@Valid @ModelAttribute InstrumentRequestDto instrument, Authentication authentication) throws MessagingException, IOException {
		boolean isAdmin = false;
	    if (authentication instanceof JwtAuthenticationToken) {
	        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
	        Jwt jwt = jwtAuthToken.getToken();
	        String tokenValue = jwt.getTokenValue();
	        Claims claims = jwtUtils.extractClaims(tokenValue);
	        String email = claims.getSubject();
	        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
	        if (userDetails != null) {
	            String roleId = (String) userDetails.get("roleId");
	            String userId = (String) userDetails.get("id");
	            if (roleId.equals("1")) {
	                isAdmin = true;
	            }
	        }
	    }

	    if (!isAdmin) {
	        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
	        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
	    }
		if(instrument.getAudio()!=null ) {
			String originalFilename = instrument.getAudio().getOriginalFilename();
            if (originalFilename != null) {
                String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
                List<String> allowedExtensions = Arrays.asList("mp3", "wav","OGG","AAC");
                if (!allowedExtensions.contains(fileExtension.toLowerCase())) {
                    throw new MessagingException("Only MP3,AAC,OGG, and WAV files are allowed");
                }
            }
			instrument.setAudioPath(fileService.uploadFile(instrument.getAudio(), FileType.CLIP));
			//
			String filename=fileService.uploadFile(instrument.getAudio() , FileType.CLIP);
	    	Resource file = fileService.loadAsResource(filename, FileType.CLIP);
	       //formRequestDto.setClipPath(filename);    
	       Path filePath = Paths.get(file.getURI());
	       System.out.println("FilePath while posting---"+filePath);
	       double durationInSeconds = audioService.getAudioDuration(filePath.toFile());
	       
	       long durationRound = (long)Math.floor(durationInSeconds);
	       long minutes = durationRound/60;
	       long seconds = durationRound%60;
	       String formattedTime = String.format("%02d:%02d", minutes, seconds);
	       instrument.setAudioDuration(formattedTime);
		}
		log.info("Update instrument ... {}", id);
		instrumentService.updateInstrument(instrument, id);
		GenericResponse response = new GenericResponse(true);
		response.setMessage(translator.toLocale(AppMessages.INSTRUMENT_UPDATED_SUCCESSFULLY));
		return response;
	}
	
	@Operation(summary = "Change action control status")
	@PutMapping("/action-control/{id}")
	public GenericResponse updateActionControlStatus(@RequestParam AccessControlStatus status, @PathVariable String id,Authentication authentication)
			throws MessagingException {
		boolean isAdmin = false;
	    if (authentication instanceof JwtAuthenticationToken) {
	        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
	        Jwt jwt = jwtAuthToken.getToken();
	        String tokenValue = jwt.getTokenValue();
	        Claims claims = jwtUtils.extractClaims(tokenValue);
	        String email = claims.getSubject();
	        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
	        if (userDetails != null) {
	            String roleId = (String) userDetails.get("roleId");
	            String userId = (String) userDetails.get("id");
	            if (roleId.equals("1")) {
	                isAdmin = true;
	            }
	        }
	    }

	    if (!isAdmin) {
	        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
	        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
	    }
		log.info("Update instrument control status ... {}", id);
		instrumentService.updateActionControlStatus(status, id);
		GenericResponse response = new GenericResponse(true);
		response.setMessage(translator.toLocale(AppMessages.INSTRUMENT_STATUS_CHANGED));
		return response;
	}
	
	@DeleteMapping("/{id}")
	public GenericResponse deleteInstrument(@PathVariable String id,Authentication authentication) {
		log.info("delete instrument.....{}",id);
		boolean isAdmin = false;
	    if (authentication instanceof JwtAuthenticationToken) {
	        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
	        Jwt jwt = jwtAuthToken.getToken();
	        String tokenValue = jwt.getTokenValue();
	        Claims claims = jwtUtils.extractClaims(tokenValue);
	        String email = claims.getSubject();
	        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
	        if (userDetails != null) {
	            String roleId = (String) userDetails.get("roleId");
	            String userId = (String) userDetails.get("id");
	            if (roleId.equals("1")) {
	                isAdmin = true;
	            }
	        }
	    }

	    if (!isAdmin) {
	        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
	        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
	    }
		instrumentService.deleteInstrument(id);
		GenericResponse response = new GenericResponse(true);
		response.setMessage(translator.toLocale(AppMessages.INSTRUMENT_DELETED));
		return response;
	}
	
    @GetMapping("/song/{filename}")
    public ResponseEntity<byte[]> serveFile(@PathVariable String filename,Authentication authentication) throws IOException, UnsupportedAudioFileException {
    	boolean isAdmin = false;
	    if (authentication instanceof JwtAuthenticationToken) {
	        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
	        Jwt jwt = jwtAuthToken.getToken();
	        String tokenValue = jwt.getTokenValue();
	        Claims claims = jwtUtils.extractClaims(tokenValue);
	        String email = claims.getSubject();
	        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
	        if (userDetails != null) {
	            String roleId = (String) userDetails.get("roleId");
	            String userId = (String) userDetails.get("id");
	            if (roleId.equals("1")) {
	                isAdmin = true;
	            }
	        }
	    }

	    if (!isAdmin) {
	        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
	        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
	    }
    	log.info("Get filename .. {}", filename);
        Resource file = fileService.loadAsResource(filename, FileType.INSTRUMENT);

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

        // Get audio duration
        Path filePath = Paths.get(file.getURI());
        double durationInSeconds = audioService.getAudioDuration(filePath.toFile());
System.out.println(durationInSeconds);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
                .header("Audio-Duration", String.valueOf(durationInSeconds)) // Add duration to headers
                .body(file.getContentAsByteArray());
    }
    
    @DeleteMapping("/")
    public GenericResponse deleteAllInstrument(@RequestBody List<String> id,Authentication authentication) {
    	boolean isAdmin = false;
	    if (authentication instanceof JwtAuthenticationToken) {
	        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
	        Jwt jwt = jwtAuthToken.getToken();
	        String tokenValue = jwt.getTokenValue();
	        Claims claims = jwtUtils.extractClaims(tokenValue);
	        String email = claims.getSubject();
	        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
	        if (userDetails != null) {
	            String roleId = (String) userDetails.get("roleId");
	            String userId = (String) userDetails.get("id");
	            if (roleId.equals("1")) {
	                isAdmin = true;
	            }
	        }
	    }

	    if (!isAdmin) {
	        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
	        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
	    }
    	log.info("delete all instrument.....{}", id);
        instrumentService.deleteAllInstrument(id);
        GenericResponse response = new GenericResponse(true);
        response.setMessage(translator.toLocale(AppMessages.INSTRUMENT_ALL_DELETED));
        return response;
    }
    
	@Operation(summary = "Change all action control status")
	@PutMapping(value ="/action-controls")
	public GenericResponse updateAllActionControlStatus(@RequestParam AccessControlStatus status, @RequestBody List<String> id, Authentication authentication)
			throws MessagingException {
		boolean isAdmin = false;
	    if (authentication instanceof JwtAuthenticationToken) {
	        JwtAuthenticationToken jwtAuthToken = (JwtAuthenticationToken) authentication;
	        Jwt jwt = jwtAuthToken.getToken();
	        String tokenValue = jwt.getTokenValue();
	        Claims claims = jwtUtils.extractClaims(tokenValue);
	        String email = claims.getSubject();
	        Map<String, Object> userDetails = (Map<String, Object>) claims.get("userDetails");
	        if (userDetails != null) {
	            String roleId = (String) userDetails.get("roleId");
	            String userId = (String) userDetails.get("id");
	            if (roleId.equals("1")) {
	                isAdmin = true;
	            }
	        }
	    }

	    if (!isAdmin) {
	        ResponseEntity<String> response = ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");
	        throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unauthorized");
	    }
		log.info("Update instrument control status ... {}", id);
		instrumentService.updateAllActionControlStatus(status, id);
		GenericResponse response = new GenericResponse(true);
		response.setMessage(translator.toLocale(AppMessages.INSTRUMENT_ALL_STATUS_CHANGED));
		return response;
	}
	
	 @GetMapping("/instrumentimage/{filename}")
	    public ResponseEntity<byte[]> serveImage(@PathVariable String filename) throws IOException, UnsupportedAudioFileException {
	        log.info("Get filename .. {}", filename);
	        Resource file = fileService.loadAsResource(filename, FileType.INSTRUMENT);

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

	        // Get audio duration
//	        Path filePath = Paths.get(file.getURI());
//	        double durationInSeconds = audioService.getAudioDuration(filePath.toFile());
	//System.out.println(durationInSeconds);
	        return ResponseEntity.ok()
	                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
//	                .header("Audio-Duration", String.valueOf(durationInSeconds)) // Add duration to headers
	                .body(file.getContentAsByteArray());
	    }
	    
	    @GetMapping("/files/imagelist")
	    public ResponseEntity<Map<String,Object>> listInstrumentFiles() throws IOException {
	        Path instrumentDirectory = fileService.getFilePathService(FileType.INSTRUMENT).getDestinationPath();
	        List<String> fileNames = Files.list(instrumentDirectory)
	                .filter(Files::isRegularFile)
	                .map(path -> path.getFileName().toString())
	                .collect(Collectors.toList());
	        int count = fileNames.size();
	        Map<String,Object> imageMap = new HashMap<>();
	        imageMap.put("count", count);
	        imageMap.put("instrumentImageList", fileNames);

	        return ResponseEntity.ok(imageMap);
	    }


}
