import CardConnect.*;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
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.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.sql.*;

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

    private JPanel dashboardPanel;
    private JLabel lbAdmin;
    private JButton btnRegister;
    private JButton btnLoad;
    private JLabel lbID;
    private JTextField tfName;
    private JTextField tfEmail;
    private JTextField tfPhone;
    private JTextField tfAccessTime;
    private JTextField tfAccess;
    private JTextField tfPass;
    private JButton btnUpdate;
    private JButton btnRegisterTC;
    private JLabel lbI;
    private JComboBox cmbAccess;

    public Dashboard() {
        setTitle("Dashborad");
        setContentPane(dashboardPanel);
        setMinimumSize(new Dimension(1000, 600));
        //setSize(1000, 600);

        //check if user table is empty
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        boolean hasRegistredUsers = connectToDatabase(1);
        //

        if (hasRegistredUsers) {
            //show Login form
            LoginDatabase loginForm = new LoginDatabase(this);
            User user = loginForm.user;

            if (user != null) {
                //lbAdmin.setText("User: " + user.name);
                setLocationRelativeTo(null);
                setVisible(true);
            }
            else {
                dispose();
            }
        }
        btnRegister.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                boolean tc = false;
                try {
                    tc = noEmptyTrustcore();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
                if (!tc) {
                    JOptionPane.showMessageDialog(Dashboard.this,
                            "0 trustcore",
                            "Successful Registration",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                }

                RegisterCard registrationForm = new RegisterCard(Dashboard.this);
                User user = registrationForm.user;

                if (user != null) {
                    JOptionPane.showMessageDialog(Dashboard.this,
                            "New user: " + user.name,
                            "Successful Registration",
                            JOptionPane.INFORMATION_MESSAGE);
                }
            }
        });
        btnLoad.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {


                //boolean cardExists = connectToDatabase(2);
                try {
                    loadCard();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
        });
        btnUpdate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                updateCard();

            }
        });
        btnRegisterTC.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                RegisterTC registrationForm = new RegisterTC(Dashboard.this);
                Trustcore trust = registrationForm.trustcore;
            }
        });
    }
    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 loadCard() throws SQLException {
        final String DB_URL = "jdbc:mysql://localhost/CardDatabase?serverTimezone=UTC";
        final String USERNAME = "root";
        final String PASSWORD = "";

        Connection conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);

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

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

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

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

        String idCard = AddonFunctions.bytesToDec(resp);

        String sqlSelectCard = "SELECT * FROM users WHERE id = '"+ idCard +"'";

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

        if(!resultSet.next()){
            JOptionPane.showMessageDialog(Dashboard.this,
                    "New card, please register it!",
                    "New card",
                    JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        lbID.setText(resultSet.getString("id"));
        tfName.setText(resultSet.getString("name"));
        tfEmail.setText(resultSet.getString("email"));
        tfPhone.setText(resultSet.getString("phone"));
        cmbAccess.addItem(resultSet.getString("accessTC"));
        tfAccessTime.setText(resultSet.getString("accessTime"));
        tfPass.setText(resultSet.getString("password"));


        statement.close();
        conn.close();


    }
    private boolean noEmptyTrustcore() throws SQLException {
        final String DB_URL = "jdbc:mysql://localhost/CardDatabase?serverTimezone=UTC";
        final String USERNAME = "root";
        final String PASSWORD = "";
        final String sql = "SELECT COUNT(*) FROM trustcore";


            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();


        return false;
    }

    private void updateCard(){
        //final String MYSQL_SERVER_URL = "jdbc:mysql://localhost/";
        final String DB_URL = "jdbc:mysql://localhost/CardDatabase?serverTimezone=UTC";
        final String USERNAME = "root";
        final String PASSWORD = "";

        String ID = lbID.getText();

        if(ID.isEmpty()){
            JOptionPane.showMessageDialog(Dashboard.this,
                    "Load card, please",
                    "error",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }

        String name = tfName.getText();
        String email = tfEmail.getText();
        String phone = tfPhone.getText();
        String accessTime = tfAccessTime.getText();
        String accessTC = cmbAccess.getSelectedItem().toString();
        String password = tfPass.getText();
        String newUserKey = " ";

        if (name.isEmpty() || email.isEmpty() || phone.isEmpty() || accessTime.isEmpty() || password.isEmpty()
                 || accessTC.isEmpty()) {
            JOptionPane.showMessageDialog(this,
                    "Please enter all fields",
                    "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;
        }

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


        try {
            //First, connect to MYSQL server and create the database if not created
            Connection conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
            final String sqlUpdate = "update users set name=?,email=?,phone=?,accessTC=?,accessTime=?,password=? where id =?";
            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(sqlUpdate);
            preparedStatement.setString(1,name);
            preparedStatement.setString(2,email);
            preparedStatement.setString(3,phone);
            preparedStatement.setString(4,accessTC);
            preparedStatement.setString(5,accessTime);
            preparedStatement.setString(6,password);
            preparedStatement.setString(7,ID);
            preparedStatement.executeUpdate();

            statement.close();
            preparedStatement.close();
            conn.close();

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException 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);

            JOptionPane.showMessageDialog(Dashboard.this,
                    "User data has been updated!",
                    "Succesfull Update",
                    JOptionPane.INFORMATION_MESSAGE);
            return;
        }

    }

    private boolean connectToDatabase(int choose) {
        boolean hasRegistredUsers = false;

        final String MYSQL_SERVER_URL = "jdbc:mysql://localhost/";
            final String DB_URL = "jdbc:mysql://localhost/CardDatabase?serverTimezone=UTC";
            final String USERNAME = "root";
            final String PASSWORD = "";

            try{
                //First, connect to MYSQL server and create the database if not created
                Connection conn = DriverManager.getConnection(MYSQL_SERVER_URL, USERNAME, PASSWORD);
                Statement statement = conn.createStatement();
            statement.executeUpdate("CREATE DATABASE IF NOT EXISTS CardDatabase");
            statement.close();
            conn.close();

            //Second, connect to the database and create the table "users" if cot created
            conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
            statement = conn.createStatement();
            //statement = conn.createStatement();
            String sqlUser = "CREATE TABLE IF NOT EXISTS users ("
                    + "id VARCHAR( 100 ) NOT NULL PRIMARY KEY,"  /*kdysi INT*/
                    + "name VARCHAR(200) NOT NULL,"
                    + "email VARCHAR(200) NOT NULL UNIQUE,"
                    + "phone VARCHAR(200),"
                    + "accessTC VARCHAR(200),"
                    + "accessTime VARCHAR(200),"
                    + "password VARCHAR(200) NOT NULL"
                    + ")";
             String sqlTrustcore = "CREATE TABLE IF NOT EXISTS trustcore ("
                     + "id VARCHAR( 100 ) NOT NULL PRIMARY KEY,"
                     + "ip VARCHAR(15) NOT NULL UNIQUE,"
                     + "nameLogin VARCHAR(20) NOT NULL,"
                     + "passwordLogin VARCHAR(30) NOT NULL,"
                     + "keyTC VARCHAR(100),"
                     + "description VARCHAR(200)"
                     + ")";
            statement.executeUpdate(sqlUser);
            statement.executeUpdate(sqlTrustcore);

            if(choose == 1) {

                //check if we have users in the table users
                statement = conn.createStatement();
                ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) FROM users");

                if (resultSet.next()) {
                    int numUsers = resultSet.getInt(1);
                    if (numUsers > 0) {
                        hasRegistredUsers = true;
                    }
                }
            }
           /* else {

                System.out.println("ESTABLISHING CONNECTION WITH THE CARD");
                ApduSender apduSender = new ApduSender(aid, (byte)MYAPP_CLA);

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

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

                if(resp.length != 16) {
                    JOptionPane.showMessageDialog(Dashboard.this,
                            "error",
                            "error",
                            JOptionPane.ERROR_MESSAGE);
                    return false;
                }
                System.out.println("hello" + AddonFunctions.bytesToDec(resp));

                String idCard = AddonFunctions.bytesToDec(resp);
                String sqlSelectCard = "SELECT * FROM users WHERE id = '"+ idCard +"'";
                statement = conn.createStatement();
                ResultSet resultSet = statement.executeQuery(sqlSelectCard);

                if(resultSet.next()){
                    lbID.setText(resultSet.getString("id"));
                    tfName.setText(resultSet.getString("name"));
                    tfEmail.setText(resultSet.getString("email"));
                    tfPhone.setText(resultSet.getString("phone"));
                    tfAccessTime.setText(resultSet.getString("accessTime"));
                    tfAccess.setText(resultSet.getString("accessTC"));
                    tfPass.setText(resultSet.getString("password"));

                    //System.out.print(resultSet.getString("id"));
                    //System.out.print(resultSet.getString("name"));
                }

            }*/

            statement.close();
            conn.close();

        }catch(Exception e){
            e.printStackTrace();
        }

        return hasRegistredUsers;
    }

    public static void main(String[] args) {

        Dashboard myForm = new Dashboard();


    }
}
