/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template
 */
package mybank;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.InputMismatchException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;

/**
 *
 * @author Verde
 */
public class MyBank {

    /**
     * @param args the command line arguments
     */

    static Scanner sc = new Scanner(System.in);
    static final String ERRORE_GENERICO = "Errore: opzione non valida.";
    static final String ERRORE_CONTI_VUOTO = "Errore: è necessario aggiungere almeno un conto corrente prima di proseguire.";
    static final String PATH_CONTI = "./src/mybank/conti/";

    public static void main(String[] args) {
        int scelta = -1;
        ArrayList<ContoCorrente> conti = importaConti();

        do {
            System.out.println("Scegliere un'opzione:");
            System.out.println("1. Aprire conto corrente");
            System.out.println("2. Versamento");
            System.out.println("3. Prelievo");
            System.out.println("4. Mostra movimenti");
            System.out.println("0. Esci");
            System.out.print("Opzione: ");

            try {
                scelta = sc.nextInt();
                sc.nextLine();

                switch (scelta) {
                    case 0:
                        break;
                    case 1:
                        aggiungiConto(conti);
                        System.out.println("Numero conto: " + conti.getLast().getNumeroContoCorrente());
                        System.out.println("Conto corrente aggiunto con successo.");
                        pausa();
                        break;
                    case 2:
                        if (conti.isEmpty()) {
                            System.out.println(ERRORE_CONTI_VUOTO);
                        } else {
                            versa(conti);
                            System.out.println("Versamento effettuato con successo.");
                        }
                        pausa();
                        break;
                    case 3:
                        if (conti.isEmpty()) {
                            System.out.println(ERRORE_CONTI_VUOTO);
                        } else {
                            preleva(conti);
                            System.out.println("Prelievo effettuato con successo.");
                        }
                        pausa();
                        break;
                    case 4:
                        if (conti.isEmpty()) {
                            System.out.println(ERRORE_CONTI_VUOTO);
                        } else {
                            stampaLog(conti);
                        }
                        pausa();
                        break;
                    default:
                        System.out.println(ERRORE_GENERICO);
                        pausa();
                        break;
                }
            } catch (InputMismatchException _) {
                System.out.println(ERRORE_GENERICO);
                pausa();
            }
        } while (scelta != 0);
    }

    public static void pausa() {
        System.out.println("Premere un tasto per continuare. . .");
        sc.nextLine();
    }

    static ArrayList<ContoCorrente> importaConti() {
        ArrayList<ContoCorrente> conti = new ArrayList<>();
        File percorsoConti = new File(PATH_CONTI);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setDateFormat(new SimpleDateFormat("dd/MM/yyyy"));
        StringBuilder sb;
        String riga;

        if (percorsoConti.exists() && percorsoConti.listFiles().length != 0) {
            for (File conto : percorsoConti.listFiles()) {
                if (conto.getName().substring(conto.getName().lastIndexOf(".")).equals(".json")) {
                    try (BufferedReader bf = new BufferedReader(new FileReader(conto))) {
                        sb = new StringBuilder();
                        riga = bf.readLine();

                        while (riga != null) {
                            sb.append(riga);
                            riga = bf.readLine();
                        }
                        conti.add(mapper.readerFor(ContoCorrente.class).readValue(sb.toString()));

                        ArrayList<Integer> numeriContiCorrenti = (ArrayList<Integer>) ContoCorrente
                                .getNumeriContiCorrenti();
                        numeriContiCorrenti.add(conti.getLast().getNumeroContoCorrente());
                        ContoCorrente.setNumeriContiCorrenti(numeriContiCorrenti);

                    } catch (Exception e) {
                        System.out.println("Errore nella lettura del file di conto corrente.");
                        System.out.println(e.getMessage());
                        System.out.println(e.getStackTrace());
                    }
                }
            }
        }
        return conti;
    }

    static void aggiungiConto(ArrayList<ContoCorrente> conti) {
        String nome;
        String cognome;
        String codiceFiscale;
        Date dataDiNascita;
        double saldoIniziale;
        int numeroContoCorrente;
        boolean error;
        ContoCorrente contoCorrente;

        do {
            error = false;
            System.out.print("Inserire il proprio nome: ");
            nome = sc.nextLine().trim();

            System.out.print("Inserire il proprio cognome: ");
            cognome = sc.nextLine().trim();

            codiceFiscale = codiceFiscale();

            dataDiNascita = dataDiNascita();

            saldoIniziale = quantita("del saldo iniziale");

            numeroContoCorrente = Math.abs(codiceFiscale.hashCode());

            if (ContoCorrente.getNumeriContiCorrenti().contains(numeroContoCorrente)) {
                System.out.println("Errore: esiste già un conto corrente per questo codice fiscale, riprovare.");
                pausa();
                error = true;
            } else {
                File percorsoConti = new File(PATH_CONTI);
                if (!percorsoConti.exists()) {
                    percorsoConti.mkdir();
                }
                contoCorrente = new ContoCorrente(nome, cognome, codiceFiscale, dataDiNascita, saldoIniziale,
                        numeroContoCorrente);
                conti.add(contoCorrente);
                salvaContoCorrente(contoCorrente);
            }
        } while (error);
    }

    static String codiceFiscale() {
        String codiceFiscale;
        boolean error;
        Pattern pattern = Pattern.compile("[A-Z]{6}[ABCDEHLMPRST]{3}\\d{2}[A-Z]\\d{3}[A-Z]");
        Matcher matcher;

        do {
            error = false;
            System.out.print("Inserire il proprio codice fiscale: ");
            codiceFiscale = sc.nextLine().trim().toUpperCase();
            matcher = pattern.matcher(codiceFiscale);
            if (!matcher.find()) {
                System.out.println(ERRORE_GENERICO);
                pausa();
                error = true;
            }
        } while (error);
        return codiceFiscale;
    }

    static Date dataDiNascita() {
        Date dataDiNascita = null;
        boolean error;
        final String FORMATO_DATA = "dd/MM/yyyy";
        SimpleDateFormat sdf = new SimpleDateFormat(FORMATO_DATA);
        sdf.setLenient(false);

        do {
            error = false;
            System.out.print("Inserire la propria data di nascita nel formato " + FORMATO_DATA + ": ");
            try {
                dataDiNascita = sdf.parse(sc.nextLine());
            } catch (ParseException _) {
                System.out.println("Errore: la data inserita non è valida.");
                pausa();
                error = true;
            }
        } while (error);
        return dataDiNascita;
    }

    static double quantita(String diCheCosa) {
        double quantita = 0;
        boolean error;

        do {
            error = false;
            System.out.print("Inserire la quantità " + diCheCosa + ": ");
            try {
                quantita = sc.nextDouble();
                sc.nextLine();

                if (quantita <= 0) {
                    System.out.println("Errore: la quantità non può essere minore o uguale a zero.");
                    pausa();
                    error = true;
                }
            } catch (InputMismatchException _) {
                System.out.println(ERRORE_GENERICO);
                pausa();
                error = true;
            }
        } while (error);

        return quantita;
    }

    static void salvaContoCorrente(ContoCorrente conto) {
        try (BufferedWriter bw = new BufferedWriter(
                new FileWriter(PATH_CONTI + "conto_" + conto.getNumeroContoCorrente() + ".json"))) {
            ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
            bw.write(ow.writeValueAsString(conto));
        } catch (IOException _) {
            System.out.println("Errore: impossibile salvare il conto corrente.");
        }
    }

    static void versa(ArrayList<ContoCorrente> conti) {
        selezionaConto(conti).versa(quantita("da versare"));
    }

    static void preleva(ArrayList<ContoCorrente> conti) {
        boolean error;

        do {
            error = false;
            try {
                selezionaConto(conti).preleva(quantita("da prelevare"));
            } catch (IllegalArgumentException e) {
                System.out.println(e.getMessage());
                pausa();
                error = true;
            }
        } while (error);

    }

    static ContoCorrente selezionaConto(ArrayList<ContoCorrente> conti) {
        ContoCorrente contoCorrente = null;
        int numeroContoCorrente;
        boolean error;

        do {
            error = false;
            System.out.print("Inserire il proprio numero di conto: ");
            numeroContoCorrente = sc.nextInt();
            sc.nextLine();

            if (!ContoCorrente.getNumeriContiCorrenti().contains(numeroContoCorrente)) {
                System.out.println("Errore: il conto corrente specificato non esiste.");
                pausa();
                error = true;
            } else {
                for (ContoCorrente conto : conti) {
                    if (conto.getNumeroContoCorrente() == numeroContoCorrente) {
                        contoCorrente = conto;
                        break;
                    }
                }
            }
        } while (error);
        return contoCorrente;
    }

    static void log(String messaggio, int numeroContoCorrente) {
        StringBuilder sb = new StringBuilder();
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.sss dd/MM/yyyy");
        try (BufferedWriter bw = new BufferedWriter(
                new FileWriter(PATH_CONTI + "movimenti_" + numeroContoCorrente + ".txt", true))) {
            sb.append("[");
            sb.append(sdf.format(new Date()));
            sb.append("] ");
            sb.append(messaggio);
            sb.append("\n");

            bw.write(sb.toString());
        } catch (IOException _) {
            System.out.println("Errore nella scrittura del movimento.");
        }
    }

    static void stampaLog(ArrayList<ContoCorrente> conti) {
        try (BufferedReader br = new BufferedReader(
                new FileReader(PATH_CONTI + "movimenti_" + selezionaConto(conti).getNumeroContoCorrente() + ".txt"))) {
            System.out.println(br.readAllAsString());
        } catch (IOException _) {
            System.out.println("Errore nella lettura dei movimenti.");
        }
    }
}
