package com.web.web_assignment;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class DatabaseService {
    private HikariDataSource dataSource;

    public DatabaseService() {
        init();
    }

    public void init() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:derby:testDB;create=true");
        config.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
        dataSource = new HikariDataSource(config);

        // Initialize the database
        try (Connection conn = getConnection()) {
            createTables(conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            String sql = "SELECT * FROM users";
            try (Connection conn = getConnection();
                 PreparedStatement stmt = conn.prepareStatement(sql)) {
                ResultSet rs = stmt.executeQuery();
                int count = 0;
                while (rs.next()) {
                    count++;
                }
                if (count == 0) {
                    loadFakeUsers();
                    loadAndSaveFakeProjects();
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void close() {
        if (dataSource != null) {
            dataSource.close();
        }
    }

    public Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    private void createTables(Connection conn) throws SQLException {
        String createUsersTable = "CREATE TABLE users (" +
                "id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, " +
                "username VARCHAR(255) UNIQUE, " +
                "name VARCHAR(255), " +
                "password VARCHAR(255), " +
                "introduction CLOB, " +
                "interests CLOB, " +
                "experiences CLOB, " +
                "skills CLOB, " +
                "careerGoals CLOB)";

        String createProjectsTable = "CREATE TABLE projects (" +
                "id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, " +
                "user_id INT, " +
                "title VARCHAR(255), " +
                "summary VARCHAR(255), " +
                "description CLOB, " +
                "keywords VARCHAR(255), " +
                "type VARCHAR(255), " +
                "collaborators VARCHAR(255), " +
                "link VARCHAR(255), " +
                "time VARCHAR(255), " +
                "FOREIGN KEY (user_id) REFERENCES users(id))";

        try {
            conn.createStatement().executeUpdate(createUsersTable);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        try {
            conn.createStatement().executeUpdate(createProjectsTable);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    public List<Project> getProjectsByUser(String username) {
        List<Project> projects = new ArrayList<>();
        String sql = "SELECT p.* FROM projects p JOIN users u ON p.user_id = u.id WHERE u.username = ?";

        try (Connection conn = getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, username);
            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {
                Project project = new Project(
                        rs.getString("title"),
                        rs.getString("summary"),
                        rs.getString("description"),
                        Arrays.asList(rs.getString("keywords").split(", ")),
                        rs.getString("type"),
                        Arrays.asList(rs.getString("collaborators").split(", ")),
                        rs.getString("link"),
                        rs.getString("time")
                );
                projects.add(project);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return projects;
    }

    public void registerUser(String username, String password) throws SQLException {
        String sql = "INSERT INTO users (username, password, name) VALUES (?, ?, ?)";
        try (Connection conn = getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, username);
            stmt.setString(2, password);
            stmt.setString(3, username);
            stmt.executeUpdate();
        }
    }

    public boolean validateUser(String username, String password) throws SQLException {
        String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
        try (Connection conn = getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, username);
            stmt.setString(2, password);
            ResultSet rs = stmt.executeQuery();
            return rs.next();
        }
    }


    // 更新用户信息的方法
    public void updateUserInfo(String username, UserInfo userInfo) throws SQLException {
        String sql = "UPDATE users SET introduction = ?, interests = ?, experiences = ?, skills = ?, careerGoals = ?, name = ? WHERE username = ?";
        try (Connection conn = getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setString(1, userInfo.getIntroduction());
            stmt.setString(2, userInfo.getInterests());
            stmt.setString(3, userInfo.getExperiences());
            stmt.setString(4, userInfo.getSkills());
            stmt.setString(5, userInfo.getCareerGoals());
            stmt.setString(6, userInfo.getName());
            stmt.setString(7, username);

            stmt.executeUpdate();
        }
    }

    public UserInfo getUserInfo(String username) throws SQLException {
        String sql = "SELECT * FROM users WHERE username = ?";
        try (Connection conn = getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, username);
            ResultSet rs = stmt.executeQuery();
            if (rs.next()) {
                return new UserInfo(
                        rs.getString("name"),
                        rs.getString("introduction"),
                        rs.getString("interests"),
                        rs.getString("experiences"),
                        rs.getString("skills"),
                        rs.getString("careerGoals"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public ArrayList<String> getAllUsers() {
        ArrayList<String> users = new ArrayList<>();
        String sql = "SELECT username FROM users";
        try (Connection conn = getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {
                users.add(rs.getString("username"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return users;
    }

    public void saveProjects(String username, List<Project> projects) throws SQLException {
        try (Connection conn = getConnection()) {
            for (Project project : projects) {
                String checkSql = "SELECT COUNT(*) FROM projects WHERE title = ? AND user_id = (SELECT id FROM users WHERE username = ?)";
                try (PreparedStatement checkStmt = conn.prepareStatement(checkSql)) {
                    checkStmt.setString(1, project.getTitle());
                    checkStmt.setString(2, username);
                    ResultSet rs = checkStmt.executeQuery();
                    rs.next();
                    int count = rs.getInt(1);

                    if (count > 0) {
                        if (count>1){
                            throw new SQLException("Duplicate project found");
                        }
                        String updateSql = "UPDATE projects SET summary = ?, description = ?, keywords = ?, type = ?, collaborators = ?, link = ?, time = ? WHERE title = ? AND user_id = (SELECT id FROM users WHERE username = ?)";
                        try (PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
                            updateStmt.setString(1, project.getSummary());
                            updateStmt.setString(2, project.getDescription());
                            updateStmt.setString(3, String.join(", ", project.getKeywords()));
                            updateStmt.setString(4, project.getType());
                            updateStmt.setString(5, String.join(", ", project.getCollaborators()));
                            updateStmt.setString(6, project.getLink());
                            updateStmt.setString(7, project.getTime());
                            updateStmt.setString(8, project.getTitle());
                            updateStmt.setString(9, username);
                            updateStmt.executeUpdate();
                        }
                    } else {
                        String insertSql = "INSERT INTO projects (user_id, title, summary, description, keywords, type, collaborators, link, time) VALUES ((SELECT id FROM users WHERE username = ?), ?, ?, ?, ?, ?, ?, ?, ?)";
                        try (PreparedStatement insertStmt = conn.prepareStatement(insertSql)) {
                            insertStmt.setString(1, username);
                            insertStmt.setString(2, project.getTitle());
                            insertStmt.setString(3, project.getSummary());
                            insertStmt.setString(4, project.getDescription());
                            insertStmt.setString(5, String.join(", ", project.getKeywords()));
                            insertStmt.setString(6, project.getType());
                            insertStmt.setString(7, String.join(", ", project.getCollaborators()));
                            insertStmt.setString(8, project.getLink());
                            insertStmt.setString(9, project.getTime());
                            insertStmt.executeUpdate();
                        }
                    }
                }
            }
        }
    }

    public void loadFakeUsers() throws SQLException {
        registerUser("admin", "admin");
        registerUser("user", "user");
        UserInfo userInfo = new UserInfo(
                "Ryan Goodwill",
                "Hello! I'm Ryan Goodwill, a passionate programmer. I'm interested in various AI models and their applications, Raspberry Pi projects, playing the piano, playing tennis, and cycling.",
                "Pascal, C++, Python, Java, Django, Raspberry Pi projects, AI model experimentation, sensor integration, control systems, web development, remote hardware control, video streaming, communication protocols.",
                "Elementary school programming with Pascal -> Learned C++ and Python -> University projects in Java (Cloud Factory Management System, Android Weather Forecast App) -> Raspberry Pi projects (infrared communication protocol, plant care box with sensors, control webpage) -> Deployed and tested Large Language Models and AI voice synthesis -> Ongoing project: video downloading, OCR, ASR, SVG conversion, LLM querying.",
                "Python, C++, Java, Pascal, Django, Raspberry Pi, AI models, Sensors, Control Systems, Web Development, Remote Hardware Control, Video Streaming, Communication Protocol Development.",
                "To work in an internet company for a few years before starting my own business."
        );
        updateUserInfo("admin", userInfo);
        updateUserInfo("user", userInfo);
    }

    public void loadAndSaveFakeProjects() throws SQLException {
        ArrayList<Project> projects = new ArrayList<>();

        Project project1 = new Project(
                "Mental Abacus Calculation Practice Tool",
                "A tool for practicing mental abacus calculations",
                "Created a mental abacus calculation practice tool using Python during high school.",
                Arrays.asList("Python", "Abacus", "Calculation"),
                "Personal Project",
                new ArrayList<>(),
                "https://github.com/heshunme/Abacus-Training-tool",
                "2020-03"
        );

        Project project2 = new Project(
                "Web fiction Crawler",
                "A tool for crawling web fiction",
                "Developed a novel web fiction crawler using Python during high school.",
                List.of(new String[]{"Python", "Crawler", "Web Fiction"}),
                "Personal Project",
                new ArrayList<>(),
                "",
                "2022-05"
        );

        Project project3 = new Project(
                "Cloud Factory Management",
                "A project management system",
                "Accomplished an assignment about a project management system named 'Cloud Factory Management' using Java during university studies.",
                List.of(new String[]{"Java", "Project Management"}),
                "Assignment",
                new ArrayList<>(),
                "",
                "2023-06"
        );

        Project project4 = new Project(
                "Weather Forecast Application",
                "An Android weather forecast application",
                "Developed a weather forecast application in my Android course during university studies.",
                List.of(new String[]{"Android", "Weather", "Java"}),
                "Assignment",
                new ArrayList<>(),
                "",
                "2024-06"
        );

        Project project5 = new Project(
                "Infrared Communication Protocol",
                "A simple protocol and drivers for infrared communication",
                "Developed a simple protocol and corresponding drivers for infrared communication using a Raspberry Pi with Python.",
                List.of(new String[]{"Python", "Raspberry Pi", "Infrared Communication"}),
                "Personal Project& Assignment",
                new ArrayList<>(),
                "",
                "2023-04"
        );

        Project project6 = new Project(
                "Plant Care Box",
                "A plant care system using Raspberry Pi",
                "Created a plant care box for the Raspberry Pi, utilizing sensors to maintain a stable environment for plants through control of a fan, stepper motor, and water pump. Built a simple control webpage with Django for remote hardware control and RTMP video streaming.",
                List.of(new String[]{"Python", "Raspberry Pi", "Django", "Sensors", "RTMP"}),
                "Assignment",
                List.of(new String[]{"Xinyang Tang", "Haochen Shi", "Zihang Yu"}),
                "",
                "2023-04"
        );

        Project project7 = new Project(
                "Large Language Models Deployment",
                "Locally deployed and tested multiple LLM projects",
                "Locally deployed and tested multiple Large Language Models (LLM) projects, including ChatGLM-6B, llama2, llama3, ChatGLM3-6B, Qwen1, Qwen1.5, Qwen2, Phi3-mini, and several versions of Stable Diffusion for AI image generation projects.",
                List.of(new String[]{"LLM", "AI", "ChatGLM", "Llama", "Stable Diffusion"}),
                "Personal Project",
                new ArrayList<>(),
                "",
                "2022-12~...(ongoing)"
        );

        Project project8 = new Project(
                "AI Voice Synthesis Projects",
                "Worked on AI voice synthesis projects",
                "Worked on AI voice synthesis projects such as so-vits-svc and GPT-SoVITS.Just for fun",
                List.of(new String[]{"AI", "Voice Synthesis", "so-vits-svc", "GPT-SoVITS"}),
                "Personal Project",
                new ArrayList<>(),
                "",
                "2024-02"
        );

        Project project9 = new Project(
                "Video Download and Analysis Project",
                "A project for downloading, analyzing, and storing videos",
                "Currently working on a project that allows downloading videos from user-specified websites, performing OCR and ASR locally, correcting errors, vectorizing data into SVG, and storing it for local LLM queries.",
                List.of(new String[]{"Video Download", "OCR", "ASR", "SVG", "LLM"}),
                "Personal Project",
                new ArrayList<>(),
                "",
                "2024-05~...(ongoing)"
        );

        projects.add(project1);
        projects.add(project2);
        projects.add(project3);
        projects.add(project4);
        projects.add(project5);
        projects.add(project6);
        projects.add(project7);
        projects.add(project8);
        projects.add(project9);
        saveProjects("admin", projects);
    }
}