import CardConnect.*;
import javax.smartcardio.ResponseAPDU;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.charset.StandardCharsets;
import java.sql.*;

public class RegisterCard extends JDialog{
    private byte[] aid = { (byte)0xf0, (byte)0x00, (byte)0x00, (byte)0x01};
    private static final byte MYAPP_CLA = (byte)0x80;
    public static final byte INS_ID = (byte)0x01;

    private JTextField tfName;
    private JTextField tfEmail;
    private JTextField tfPhone;
    private JTextField tfAccess;
    private JPasswordField tfPass;
    private JPasswordField tfPass2;
    private JButton btnRegister;
    private JButton btnCancel;
    private JPanel registerPanel;
    private JTextField tbID;
    private JComboBox cmbAccess;
    private JLabel lbID;

    public RegisterCard(JFrame parent) {
        super(parent);
        setTitle("Create a new account");
        setContentPane(registerPanel);
        setMinimumSize(new Dimension(600, 474));
        setModal(true);
        setLocationRelativeTo(parent);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        updateComboTrustcore();
        if(loadCardID()){
            JOptionPane.showMessageDialog(RegisterCard.this,
                    "karta existuje",
                    "error",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }

        btnRegister.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                registerUser();
            }
        });
        btnCancel.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });

        setVisible(true);
    }

    private boolean loadCardID(){

        APDU apduSender = new APDU(aid, MYAPP_CLA);

        ResponseAPDU response = apduSender.SendApdu(INS_ID, new byte[0], (byte)0);

        byte[] resp = AddonFunctions.checkSW(response.getBytes());

        if(resp.length != 16) {
            JOptionPane.showMessageDialog(RegisterCard.this,
                    "error",
                    "error",
                    JOptionPane.ERROR_MESSAGE);
            return true;
        }

        if(checkCardExists(AddonFunctions.bytesToDec(resp))){
            return true;
        }

        lbID.setText(AddonFunctions.bytesToDec(resp));
        return false;
    }

    private boolean checkCardExists(String CardID){
        final String DB_URL = "jdbc:mysql://localhost/CardDatabase?serverTimezone=UTC";
        final String USERNAME = "root";
        final String PASSWORD = "";
        final String sql = "SELECT COUNT(id) FROM users WHERE id = '"+CardID+"'";

        try{
            Connection conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
            Statement stmt = conn.createStatement();
            ResultSet resultSet = stmt.executeQuery(sql);

            if (resultSet.next()) {
                int numUsers = resultSet.getInt(1);
                if (numUsers > 0) {
                    return true;
                }
            }

            stmt.close();
            conn.close();

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return false;

    }

    private void updateComboTrustcore() {
        final String DB_URL = "jdbc:mysql://localhost/CardDatabase?serverTimezone=UTC";
        final String USERNAME = "root";
        final String PASSWORD = "";
        final String sql = "SELECT * from trustcore";

        try{
            Connection conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
            Statement stmt = conn.createStatement();
            ResultSet resultSet = stmt.executeQuery(sql);

            while (resultSet.next()){
                cmbAccess.addItem(resultSet.getString("description"));
            }

            stmt.close();
            conn.close();

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

    }

    private void registerUser() {
        String ID = lbID.getText();
        String name = tfName.getText();
        String email = tfEmail.getText();
        String phone = tfPhone.getText();
        String accessTime = tfAccess.getText();
        String accessTC = cmbAccess.getSelectedItem().toString();
        //String accessTC = tfTC.getText();
        String password = String.valueOf(tfPass.getPassword());
        String confirmPassword = String.valueOf(tfPass2.getPassword());

        if (name.isEmpty() || email.isEmpty() || phone.isEmpty() || accessTime.isEmpty() || password.isEmpty()
        || ID.isEmpty() || accessTC.isEmpty()) {
            JOptionPane.showMessageDialog(this,
                    "Please enter all fields",
                    "Try again",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }

        if (!password.equals(confirmPassword)) {
            JOptionPane.showMessageDialog(this,
                    "Confirm Password does not match",
                    "Try again",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }

        if(!accessTime.matches("\\d{2}:\\d{2}-\\d{2}:\\d{2}") && !(accessTime.matches("\\d{1}:\\d{2}-\\d{2}:\\d{2}")) && !accessTime.matches("\\d{1}:\\d{2}-\\d{1}:\\d{2}")){
            JOptionPane.showMessageDialog(this,
                    "Please enter valid time format, format hh:mm-hh:mm",
                    "Try again",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }

        user = addUserToDatabase(ID, name, email, phone, accessTime,accessTC, password);
        if (user != null) {
            dispose();
        }
        else {
            JOptionPane.showMessageDialog(this,
                    "Failed to register new user",
                    "Try again",
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    public User user;
    private User addUserToDatabase(String ID,String name, String email, String phone, String accessTime,String accessTC, String password) {
        User user = null;
        final String DB_URL = "jdbc:mysql://localhost/CardDatabase?serverTimezone=UTC";
        final String USERNAME = "root";
        final String PASSWORD = "";
        String newUserKey = " ";

        byte[] takeDataFromFields = (name + "," + email + "," + phone + "," + accessTC + "," + accessTime + "," + password + "*").getBytes(StandardCharsets.UTF_8);


        try{
            Connection conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
            // Connected to database successfully...

            //Statement stmt = conn.createStatement();
            final String InsertSQL = "INSERT INTO users (id, name, email, phone, accessTC, accessTime, password) " +
                    "VALUES (?, ?, ?, ?, ?, ?, ?)";
            final String sqlKeyTC = "SELECT keyTC FROM trustcore WHERE description='"+accessTC+"'";

            Statement statement = conn.createStatement();
            ResultSet resultSet = statement.executeQuery(sqlKeyTC);

            if (resultSet.next()) {
                //System.out.println(resultSet.getString("keyTC"));
                newUserKey = AddonFunctions.genUserKey(ID, resultSet.getString("keyTC"));
                System.out.println(newUserKey);
            }

            PreparedStatement preparedStatement = conn.prepareStatement(InsertSQL);
            preparedStatement.setString(1, ID);
            preparedStatement.setString(2, name);
            preparedStatement.setString(3, email);
            preparedStatement.setString(4, phone);
            preparedStatement.setString(5, accessTC);
            preparedStatement.setString(6, accessTime);
            preparedStatement.setString(7, password);

            //Insert row into the table
            int addedRows = preparedStatement.executeUpdate();
            if (addedRows > 0) {
                user = new User();
                user.ID = ID;
                user.name = name;
                user.email = email;
                user.phone = phone;
                user.access = accessTC;
                user.accessTime = accessTime;
                user.password = password;
            }

            statement.close();
            preparedStatement.close();
            //stmt.close();
            conn.close();
        }catch(Exception e){
            e.printStackTrace();
        }

        APDU apduSender = new APDU(aid, (byte)MYAPP_CLA);

        if(newUserKey != " ") {
            ResponseAPDU response = apduSender.SendApdu((byte) 0x10, AddonFunctions.decTobytes(newUserKey), (byte) 0);
            System.out.println(AddonFunctions.bytesToDec(response.getBytes()));
        }

        ResponseAPDU response2 = apduSender.SendApdu((byte) 0x50, takeDataFromFields, (byte) 0);

        return user;
    }

    public static void main(String[] args) {
        RegisterCard myForm = new RegisterCard(null);
        User user = myForm.user;
        if (user != null) {
            System.out.println("Successful registration of: " + user.name);
        } else {
            System.out.println("Registration canceled");
        }
    }
}
