/*
UNIVERSIDAD ESTATAL A DISTANCIA
ESCUELAS DE CIENCIAS EXACTAS Y NATURALES
CATEDRA TECNOLOGÍA DE SISTEMAS

ANDRES ALBERTO SANCHEZ TREJOS
GRUPO 09
TUTOR: HERSANN FONSECA QUIRÓS
PROGRAMACION INTERMEDIA 00824
Proyecto #1
IC2026


Bibliografía
Deitel, P.J.D. H. (2021). Cómo Programar En Java. Pearson HispanoAmerica Contenido. https://bookshelf.vitalsource.com/books/9786073255400
https://www.w3schools.com/java/
CODEX: se usó para generalmente para revisar la eficacia de las cláses y métodos. 
El prompt generalmente utilizado fue "revisa esta método/función" o fué utilizado .

 */
package parqueo;

import java.util.Scanner;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {

    private static final DateTimeFormatter fechaHora = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");

    public static void main(String[] args) throws Exception {
        GestorParqueo gestorParqueo = new GestorParqueo();

        Scanner entrada = new Scanner(System.in);
        int opcion = 0;

        System.out.println("=================================");
        System.out.println("Bienvenido al sistema de parqueo");
        System.out.println("=================================");
        LocalDate fechaAc = LocalDate.now();
        System.out.println("Fecha actual: " + fechaAc);

        while (opcion != 5) {
            System.out.println("1. Registrar ingreso de vehículo");
            System.out.println("2. Registrar salida de vehículo");
            System.out.println("3. Consultar espacios disponibles");
            System.out.println("4. Ver reportes del día");
            System.out.println("5. Salir");
            System.out.println("Seleccione una opción:");
            opcion = intValida(entrada);

            switch (opcion) {
                case 1:
                    TiqueteParqueo nuevoTiquete = registrarIngreso(entrada, gestorParqueo);
                    if (nuevoTiquete != null) {
                        if (gestorParqueo.registrarIngreso(nuevoTiquete)) {
                            System.out.println("Ingreso registrado correctamente.");
                            System.out.println("Espacios disponible: " + gestorParqueo.espaciosDisponibles() + "/10");
                            if (gestorParqueo.espaciosDisponibles() <= 5) {
                                System.err.println("Advertencia: Se ha alcanzado el 50% de capacidad máxima");
                            }
                            if (gestorParqueo.espaciosDisponibles() == 10) {
                                System.out.println("Advertencia: Se ha alcanzado la capacidad máxima 10/10.");
                            }
                        } else {
                            System.out.println("No hay espacios disponibles.");
                        }
                    }
                    regresarMenuPrincipal(entrada);
                    break;
                case 2:
                    if (!gestorParqueo.estaVacio()) {
                        registrarSalida(entrada, gestorParqueo);
                    } else {
                        System.out.println("No hay vehiculos registrados.");
                    }
                    regresarMenuPrincipal(entrada);
                    break;
                case 3:
                    System.out.println("Espacios disponibles: " + gestorParqueo.espaciosDisponibles());
                    regresarMenuPrincipal(entrada);
                    break;
                case 4:
                    mostrarMenuReportes(entrada, gestorParqueo);
                    regresarMenuPrincipal(entrada);
                    break;
                case 5:
                    System.out.println("Saliendo del sistema de parqueo.");
                    break;
                default:
                    System.out.println("Opción inválida. Por favor, seleccione una opción válida.");
                    regresarMenuPrincipal(entrada);
                    break;
            }

        }

        entrada.close();
    }

    private static TiqueteParqueo registrarIngreso(Scanner entrada, GestorParqueo gestorParqueo) {
        String placa = placaValida(entrada);
        if (gestorParqueo.existePlaca(placa)) {
            System.out.println("La placa ingresada ya está registrada.");
            return null;
        }

        int tipo = -1;
        boolean tipoValido = false;
        while (!tipoValido) {
            System.out.println("Ingrese el tipo de vehículo (1 para Automóvil, 2 para Motocicleta, 3 para Camión):");
            tipo = intValida(entrada);
            if (tipo >= 1 && tipo <= 3) {
                tipoValido = true;
            } else {
                System.out.println("Opción inválida. Por favor, seleccione una opción válida.");
            }
        }

        TiqueteParqueo.TipoServicio modalidad = setModalidad(entrada);

        try {
            Vehiculo vehiculo = switch (tipo) {
                case 1 ->
                    new Automovil(placa);
                case 2 ->
                    new Motocicleta(placa);
                case 3 ->
                    new Camion(placa);
                default ->
                    throw new IllegalArgumentException("Tipo inválido.");
            };
            return new TiqueteParqueo(vehiculo, LocalDateTime.now(), modalidad);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
            return null;
        }
    }

    private static void registrarSalida(Scanner entrada, GestorParqueo gestorParqueo) {

        String placa = placaValida(entrada);
        TiqueteParqueo tiquete = gestorParqueo.buscarTiqueteAbierto(placa);

        if (tiquete == null) {
            System.out.println("Placa no se encuentra registrada en el sistema.");
        } else {
            tiquete.setHoraSalida(LocalDateTime.now());
            CalculoTarifa calculadora = new CalculoTarifa();
            CalculoTarifa.DetalleCobro detalle = calculadora.calcularDetalle(tiquete);
            int monto = detalle.getTotal();
            tiquete.setMontoTotal(monto);
            gestorParqueo.registrarSalida(placa);

            String horaEntrada = tiquete.getHoraEntrada().format(fechaHora);
            String horaSalida = tiquete.getHoraSalida().format(fechaHora);
            double tiempoHoras = detalle.getMinutos() / 60.0;

            System.out.println("****************************************");
            System.out.println("RECIBO DE PARQUEO");
            System.out.println("****************************************");
            System.out.println("Placa: " + tiquete.getVehiculo().getPlaca());
            System.out.println("Tipo: " + tiquete.getVehiculo().getNombre());
            System.out.println("Tipo de servicio: " + tipoServicioTexto(tiquete.getModalidad()));
            System.out.println("Hora de entrada: " + horaEntrada);
            System.out.println("Hora de salida: " + horaSalida);
            System.out.println("Tiempo de permanencia (horas): " + String.format("%.2f", tiempoHoras));
            if (tiquete.getModalidad() == TiqueteParqueo.TipoServicio.POR_HORA) {
                System.out.println("Costo por hora: CRC " + detalle.getTarifaAplicada());
            } else {
                System.out.println("Costo por hora: No aplica (servicio por día)");
            }
            System.out.println("Subtotal: CRC " + detalle.getSubtotal());
            if (detalle.getDescuento() > 0) {
                System.out.println("Descuento: CRC " + detalle.getDescuento());
            } else {
                System.out.println("Descuento: No aplica");
            }
            System.out.println("========================================");
            System.out.println("TOTAL A PAGAR: CRC " + monto);
            System.out.println("========================================");
            System.out.println("Gracias por usar nuestros servicios");
        }

    }

    private static void mostrarMenuReportes(Scanner entrada, GestorParqueo gestorParqueo) {
        ReporteParqueo reporteParqueo = new ReporteParqueo();
        int opcionReporte = 0;

        while (opcionReporte != 4) {
            System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
            System.out.println("+                  Menú de reportes del día               +");
            System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
            System.out.println("1. Listado de vehículos");
            System.out.println("2. Total recaudado por tipo de servicio");
            System.out.println("3. Estadísticas básicas de uso del parqueo");
            System.out.println("4. Volver al menú principal");
            System.out.println("Seleccione una opción:");
            opcionReporte = intValida(entrada);

            switch (opcionReporte) {
                case 1:
                    reporteParqueo.vehiculosDia(gestorParqueo, LocalDate.now());
                    break;
                case 2:
                    reporteParqueo.totalUtilServicio(gestorParqueo, LocalDate.now());
                    break;
                case 3:
                    reporteParqueo.estadisticasBasicas(gestorParqueo, LocalDate.now());
                    break;
                case 4:
                    System.out.println("Regresando al menú principal.");
                    break;
                default:
                    System.out.println("Opción inválida. Por favor, seleccione una opción válida.");
                    break;
            }
        }
    }

    // define el tipo de servicio (modalida por dia o por hora)
    private static TiqueteParqueo.TipoServicio setModalidad(Scanner entrada) {
        int modalidad = -1;
        while (modalidad != 1 && modalidad != 2) {
            System.out.println("Seleccione modalidad de cobro (1 por hora, 2 por día):");
            modalidad = intValida(entrada);
            if (modalidad != 1 && modalidad != 2) {
                System.out.println("Opción inválida. Por favor, seleccione una opción válida.");
            }
        }

        if (modalidad == 1) {
            return TiqueteParqueo.TipoServicio.POR_HORA;
        }
        return TiqueteParqueo.TipoServicio.POR_DIA;
    }

    private static int intValida(Scanner entrada) {
        int opcion = -1;
        try {
            opcion = Integer.parseInt(entrada.nextLine().trim());
        } catch (NumberFormatException e) {
            System.out.println("Error: Entrada inválida. Por favor, ingrese un número entero.");
        }
        return opcion;
    }

    private static void regresarMenuPrincipal(Scanner entrada) {
        System.out.println("Presione Enter para volver al menú principal...");
        entrada.nextLine();
    }

    private static String placaValida(Scanner entrada) {
        String placa = "";
        boolean placaValida = false;
        while (!placaValida) {
            System.out.println("Ingrese la placa del vehículo (en formato ABC123):");
            placa = entrada.nextLine().trim().toUpperCase();
            if (placa.isEmpty()) {
                System.out.println("La placa no puede estar vacía.");
            } else if (!Vehiculo.esPlacaValida(placa)) {
                System.out.println("Formato inválido. Use 3 letras y 3 números (ejemplo: ABC123).");
            } else {
                placaValida = true;
            }
        }
        return placa;
    }

    private static String tipoServicioTexto(TiqueteParqueo.TipoServicio modalidad) {
        if (modalidad == TiqueteParqueo.TipoServicio.POR_HORA) {
            return "Por hora";
        }
        return "Por día";
    }

}
