/**
 * 
 */
package org.lapaloma.proyectos;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.net.URL;
import java.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.lapaloma.proyectos.util.ConversorTipos;
import org.lapaloma.proyectos.util.GestorClientesServiciosAWS;

import com.opencsv.bean.CsvToBeanBuilder;

import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
import software.amazon.awssdk.services.s3.model.S3Exception;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;

/**
 * Clase principal encargada de probar el acceso a datos con los servicios S3 y
 * DynamoDb de AWS
 * 
 * @author Programador: Isidoro Nevares Martín - Virgen de la Paloma
 * @date 25 may 2025
 * @version: 1.0
 */
public class ClasePrincipal {
	private final static String NOMBRE_TABLA = "ddb-hitos-proyecto";
	private final static String NOMBRE_BUCKET = "s3-objetos-proyecto";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ClasePrincipal cp = new ClasePrincipal();
		// Probar almacenamiento en DynamoDb (dentro se almacena documento en S3)
		cp.almacenarEstructuraHitosDynamoDB();

		// Ejemplo de hito obtenido de un interfaz gráfico.
		Hito hito = new Hito();
		hito.setIdProyecto(1);
		hito.setNumeroHito(2);
	    Date fechaHito = ConversorTipos.convertirStringADate("2025-04-15T14:30:00");
		hito.setFechaHito(fechaHito);
		File documentoAEnviar = new File("ficheros//Kingdom Town for Gods.pdf");
		hito.setDocumento(documentoAEnviar);
		Date fechaEnvio = new Date(); // Contiene la fecha y hora actuales
		hito.setFechaEnvio(fechaEnvio);
		hito.setIdAlumnoEnvio(1); // Identificador del Alumn@ que realizó la entrega.
		hito.setResumenEntrega("Cambios en el Diagrama de Casos de Uso.");
		hito.setEstado("Enviado con retraso");

		// Almacenamiento de un documento/imagen en un Bucket de S3
		cp.almacenarDocumentacionHitoEnS3(hito);

		// Actualizar información en DynamoDb con información Hito
		cp.actualizarHitoDynamoDb(hito);

		// Consultar hito en DynamoDB
		hito = cp.obtenerHitoProyectoPorClave(hito.getIdProyecto(), hito.getNumeroHito());
		System.out.println(hito);

		// Obtener información de S3
		String urlDocumentoS3 = cp.obtenerURLObjetoS3(hito.getClaveDocumentoS3());
		System.out.println(urlDocumentoS3);

	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void almacenarEstructuraHitosDynamoDB() {
		List<Hito> listaHitos = null;
		try {
			listaHitos = new CsvToBeanBuilder(new FileReader("ficheros/hitos-proyecto.csv")).withType(Hito.class)
					.withSeparator('|').build().parse();
			for (Hito hitoCSV : listaHitos) {
				System.out.println(hitoCSV);
				// Crear un registro en una tabla DynamoDB
				crearHitoDynamoDb(hitoCSV);
			}
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void crearHitoDynamoDb(Hito hito) {
		// Crear el cliente de DynamoDB (usando SDK v2)
		DynamoDbClient clienteDynamoDb = GestorClientesServiciosAWS.getClienteDynamoDB();

		// Crear un ítem con los atributos de un Hito
		String fechaHitoString = "";
		if (hito.getFechaHito() != null)
			fechaHitoString = ConversorTipos.convertirDateAString(hito.getFechaHito());

		PutItemRequest putItemRequest = PutItemRequest.builder().tableName(NOMBRE_TABLA)
				.item(Map.of("id_proyecto", AttributeValue.builder().n(String.valueOf(hito.getIdProyecto())).build(),
						"numero_hito", AttributeValue.builder().n(String.valueOf(hito.getNumeroHito())).build(),
						"fecha_hito", AttributeValue.builder().s(fechaHitoString).build()))
				.build();

		// Insertar el ítem en DynamoDB
		try {
			clienteDynamoDb.putItem(putItemRequest);
			System.out.println("Ítem agregado exitosamente.");
		} catch (DynamoDbException e) {
			System.err.println("No se pudo insertar el ítem: " + e.getMessage());
			e.printStackTrace();
		} finally {
			clienteDynamoDb.close();
		}
	}

	private void actualizarHitoDynamoDb(Hito hito) {
		// Crear el cliente de DynamoDB (usando SDK v2)
		DynamoDbClient clienteDynamoDb = GestorClientesServiciosAWS.getClienteDynamoDB();

		// Crear un ítem con los atributos de un Hito
		String fechaHitoString = "";
		if (hito.getFechaHito() != null)
			fechaHitoString = ConversorTipos.convertirDateAString(hito.getFechaHito());

		String fechaEnvioString = "";
		if (hito.getFechaEnvio() != null)
			fechaEnvioString = ConversorTipos.convertirDateAString(hito.getFechaEnvio());

		String sIdAlumno = "";
		if (hito.getIdAlumnoEnvio() != null)
			sIdAlumno = String.valueOf(hito.getIdAlumnoEnvio());

		// Información del bucket y del archivo a subir
		String claveDocumento = hito.getIdProyecto() + "/" + hito.getNumeroHito() + "/" + hito.getDocumento().getName();

		PutItemRequest putItemRequest = PutItemRequest.builder().tableName(NOMBRE_TABLA)
				.item(Map.of("id_proyecto", AttributeValue.builder().n(String.valueOf(hito.getIdProyecto())).build(),
						"numero_hito", AttributeValue.builder().n(String.valueOf(hito.getNumeroHito())).build(),
						"fecha_hito", AttributeValue.builder().s(fechaHitoString).build(), 
						"fecha_envio", AttributeValue.builder().s(fechaEnvioString).build(), 
						"id_alumno_envio", AttributeValue.builder().s(sIdAlumno).build(), 
						"clave_documento", AttributeValue.builder().s(claveDocumento).build(), 
						"resumen_entrega", AttributeValue.builder().s(hito.getResumenEntrega()).build(),
						"estado", AttributeValue.builder().s(String.valueOf(hito.getEstado())).build()))
				.build();

		// Insertar el ítem en DynamoDB
		try {
			clienteDynamoDb.putItem(putItemRequest);
			System.out.println("Ítem agregado exitosamente.");
		} catch (DynamoDbException e) {
			System.err.println("No se pudo insertar el ítem: " + e.getMessage());
			e.printStackTrace();
		} finally {
			clienteDynamoDb.close();
		}
	}

	private void almacenarDocumentacionHitoEnS3(Hito hito) {
		// Crear el cliente de S3 (usando SDK v2)
		S3Client clienteS3 = GestorClientesServiciosAWS.getClienteBucketS3();

		// Información del bucket y del archivo a subir
		String claveDocumento = hito.getIdProyecto() + "/" + hito.getNumeroHito() + "/" + hito.getDocumento().getName();

		// Solicitud para subir el archivo
		PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(NOMBRE_BUCKET).key(claveDocumento)
				.build();

		try {
			// Realizar la carga del archivo
			PutObjectResponse response = clienteS3.putObject(putObjectRequest, hito.getDocumento().toPath());

			// Imprimir respuesta de éxito
			System.out.println("Archivo subido correctamente. ETag: " + response.eTag());
		} catch (S3Exception e) {
			System.err.println("No se pudo insertar el ítem: " + e.getMessage());
			e.printStackTrace();
		} finally {
			clienteS3.close();
		}

	}

	public Hito obtenerHitoProyectoPorClave(int idProyecto, int numeroHito) {
		Hito hito = null;

		// Crear el cliente de DynamoDB (usando SDK v2)
		DynamoDbClient clienteDynamoDb = GestorClientesServiciosAWS.getClienteDynamoDB();

		// Clave para la consulta
		Map<String, AttributeValue> clave = new HashMap<>();
		clave.put("id_proyecto", AttributeValue.builder().n(String.valueOf(idProyecto)).build());
		clave.put("numero_hito", AttributeValue.builder().n(String.valueOf(numeroHito)).build());

		// Construir la petición
		GetItemRequest request = GetItemRequest.builder().tableName(NOMBRE_TABLA).key(clave).build();

		// Realizar consulta
		GetItemResponse response = clienteDynamoDb.getItem(request);

		if (response.hasItem()) {
			hito = new Hito();

			Map<String, AttributeValue> item = response.item();

			// Recuperar valores
			String sFechaHito = item.get("fecha_hito").s();
			String sFechaEnvio = item.get("fecha_envio").s();
			String idAlumnoEnvio = item.get("id_alumno_envio").s();
			String claveDocumento = item.get("clave_documento").s();
			String resumenEntrega = item.get("resumen_entrega").s();
			String estado = item.get("estado").s();

			Date fechaHito = ConversorTipos.convertirStringADate(sFechaHito);
			Date fechaEnvio = ConversorTipos.convertirStringADate(sFechaEnvio);

			hito.setIdProyecto(idProyecto);
			hito.setNumeroHito(numeroHito);
			hito.setFechaHito(fechaHito);
			hito.setIdAlumnoEnvio(Integer.parseInt(idAlumnoEnvio));
			hito.setFechaEnvio(fechaEnvio);
			hito.setResumenEntrega(resumenEntrega);
			hito.setEstado(estado);
			hito.setClaveDocumentoS3(claveDocumento);

		} else {
			System.out.println("No se encontró el hito para la clave dada.");
		}

		clienteDynamoDb.close();
		return hito;
	}

	private String obtenerURLObjetoS3(String claveDocumento) {
		String urlObjetoS3 = null;
		// Crear el cliente de S3 (usando SDK v2)
		S3Client clienteS3 = GestorClientesServiciosAWS.getClienteBucketS3();

		// Usar el perfil `learnerlab-profile` (el nombre del perfil en
		// `~/.aws/credentials`)
		ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create("default");

		// Crear el cliente presigner de S3 con el perfil específico
		S3Presigner presigner = S3Presigner.builder().region(GestorClientesServiciosAWS.REGION_AWS)
				.credentialsProvider(credentialsProvider) // Usar el perfil especificado
				.build();

		// Crear la solicitud de obtención de objeto
		GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(NOMBRE_BUCKET).key(claveDocumento)
				.build();

		// Generar la URL firmada
		PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(
				builder -> builder.getObjectRequest(getObjectRequest).signatureDuration(Duration.ofMinutes(60)) // Duración
																												// de la
																												// URL
																												// firmada
		);

		// Obtener la URL firmada
		URL presignedUrl = presignedRequest.url();
		urlObjetoS3 = presignedUrl.toString();

		// Cerrar el presigner
		presigner.close();

		return urlObjetoS3;
	}

}
