package easydo.technology.core.processors;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;

import easydo.technology.core.FactoryProjectInfo;
import easydo.technology.core.FactoryProjectInfoPosition;
import easydo.technology.core.SpringRequestUser;
import zmo.technology.lite.core.ZeroProcessor;
import zmo.technology.lite.core.ZeroRequestGuider;

public class UserProcessor extends ZeroProcessor {

    protected UserProcessor(ZeroRequestGuider guider) {
        super(guider);
    }

    public static UserProcessor build(ZeroRequestGuider guider) {
        return new UserProcessor(guider);
    }

    private PreparedStatement fetchProjectInfoByIDPrepared() throws SQLException {
        final String fetchProjectInfoByID = "SELECT * FROM factory_project_info_view WHERE fpi_id = ?";
        if (!existsPreparedStatement(fetchProjectInfoByID))
            registeyPreparedStatement(fetchProjectInfoByID);
        return preparedStatement(fetchProjectInfoByID);
    }

    public FactoryProjectInfo fetchProjectInfoByID(long fpiID) throws SQLException {
        fetchProjectInfoByIDPrepared().setLong(1, fpiID);
        ResultSet set = fetchProjectInfoByIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("project info : " + fpiID + " not found");
        return new FactoryProjectInfo(set);
    }

    private PreparedStatement fetchUserProjectInfosPrepared() throws SQLException {
        final String fetchUserProjectInfos = "SELECT dept_id ,project_fpi_id FROM sys_user WHERE user_id = ?";
        if (!existsPreparedStatement(fetchUserProjectInfos))
            registeyPreparedStatement(fetchUserProjectInfos);
        return preparedStatement(fetchUserProjectInfos);
    }

    public SpringRequestUser fetchUserProjectInfos(SpringRequestUser user) throws SQLException {
        fetchUserProjectInfosPrepared().setLong(1, user.getUserID());
        ResultSet set = fetchUserProjectInfosPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("user not found");
        user.setDeptID(set.getLong("DEPT_ID"));
        if (set.getObject("PROJECT_FPI_ID") != null)
            user.addProjectInfo(fetchProjectInfoByID(set.getLong("PROJECT_FPI_ID")));
        return user;
    }

    private PreparedStatement fetchDeptProjectInfosPrepared() throws SQLException {
        final String fetchDeptProjectInfos = "SELECT a.* FROM factory_project_info_view a ,factory_project_belong b WHERE b.dept_id = ? AND a.fpi_id = b.project_id";
        if (!existsPreparedStatement(fetchDeptProjectInfos))
            registeyPreparedStatement(fetchDeptProjectInfos);
        return preparedStatement(fetchDeptProjectInfos);
    }

    public List<FactoryProjectInfo> fetchDeptProjectInfos(SpringRequestUser user) throws SQLException {
        fetchDeptProjectInfosPrepared().setLong(1, user.getDeptID());
        ResultSet set = fetchDeptProjectInfosPrepared().executeQuery();
        user.setProjectInfos(new ArrayList<>());
        while (set.next())
            user.getProjectInfos().add(new FactoryProjectInfo(set));
        return user.getProjectInfos();
    }

    private PreparedStatement fetchChildDeptIDsPrepared() throws SQLException {
        final String fetchChildDeptIDs = "SELECT dept_id FROM sys_dept WHERE pid = ?";
        if (!existsPreparedStatement(fetchChildDeptIDs))
            registeyPreparedStatement(fetchChildDeptIDs);
        return preparedStatement(fetchChildDeptIDs);
    }

    public Set<Long> fetchChildDeptIDs(long parentID) throws SQLException {
        fetchChildDeptIDsPrepared().setLong(1, parentID);
        ResultSet set = fetchChildDeptIDsPrepared().executeQuery();
        Set<Long> deptIDs = new HashSet<>();
        while (set.next())
            deptIDs.add(set.getLong(1));
        return deptIDs;
    }

    private PreparedStatement fetchChildDeptProjectInfosPrepared() throws SQLException {
        final String fetchChildDeptProjectInfos = "SELECT c.* FROM sys_dept a ,factory_project_belong b ,factory_project_info_view c WHERE a.pid = ? AND a.dept_id = b.dept_id AND b.project_id = c.fpi_id";
        if (!existsPreparedStatement(fetchChildDeptProjectInfos))
            registeyPreparedStatement(fetchChildDeptProjectInfos);
        return preparedStatement(fetchChildDeptProjectInfos);
    }

    public List<FactoryProjectInfo> fetchChildDeptProjectInfos(long parentID) throws SQLException {
        fetchChildDeptProjectInfosPrepared().setLong(1, parentID);
        ResultSet set = fetchChildDeptProjectInfosPrepared().executeQuery();
        List<FactoryProjectInfo> projectInfos = new ArrayList<>();
        while (set.next())
            projectInfos.add(new FactoryProjectInfo(set));
        return projectInfos;
    }

    private PreparedStatement fetchAllProjectInfosPrepared() throws SQLException {
        final String fetchAllProjectInfos = "SELECT * FROM factory_project_info_view";
        if (!existsPreparedStatement(fetchAllProjectInfos))
            registeyPreparedStatement(fetchAllProjectInfos);
        return preparedStatement(fetchAllProjectInfos);
    }

    public List<FactoryProjectInfo> fetchAllProjectInfos(SpringRequestUser user) throws SQLException {
        ResultSet set = fetchAllProjectInfosPrepared().executeQuery();
        user.setProjectInfos(new ArrayList<>());
        while (set.next())
            user.getProjectInfos().add(new FactoryProjectInfo(set));
        return user.getProjectInfos();
    }

    private PreparedStatement fetchAllProjectInfoPositionPrepared() throws SQLException {
        final String fetchAllProjectInfoPosition = "SELECT * FROM factory_project_position WHERE project_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchAllProjectInfoPosition))
            registeyPreparedStatement(fetchAllProjectInfoPosition);
        return preparedStatement(fetchAllProjectInfoPosition);
    }

    public FactoryProjectInfoPosition fetchAllProjectInfoPosition(FactoryProjectInfo project) throws SQLException {
        fetchAllProjectInfoPositionPrepared().setLong(1, project.getFpiID());
        ResultSet set = fetchAllProjectInfoPositionPrepared().executeQuery();
        if (!set.next())
            return null;
        project.setPosition(new FactoryProjectInfoPosition(set));
        return project.getPosition();
    }

    private PreparedStatement fetchUserIDByUsernamePrepared() throws SQLException {
        final String fetchUserIDByUsername = "SELECT user_id FROM sys_user WHERE username = ? LIMIT 1";
        if (!existsPreparedStatement(fetchUserIDByUsername))
            registeyPreparedStatement(fetchUserIDByUsername);
        return preparedStatement(fetchUserIDByUsername);
    }

    public long fetchUserIDByUsername(String username) throws SQLException {
        fetchUserIDByUsernamePrepared().setString(1, username);
        ResultSet set = fetchUserIDByUsernamePrepared().executeQuery();
        if (!set.next())
            throw new SQLException("user `" + username + "` not found");
        return set.getLong(1);
    }

    private PreparedStatement fetchUsernameByUserIDPrepared() throws SQLException {
        final String fetchUsernameByUserID = "SELECT username FROM sys_user WHERE user_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchUsernameByUserID))
            registeyPreparedStatement(fetchUsernameByUserID);
        return preparedStatement(fetchUsernameByUserID);
    }

    public String fetchUsernameByUserID(long userID) throws SQLException {
        fetchUsernameByUserIDPrepared().setLong(1, userID);
        ResultSet set = fetchUsernameByUserIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("user id `" + userID + "` not found");
        return set.getString(1);
    }

    /// -- wx open id

    private PreparedStatement addUserWxOpenIDPrepared() throws SQLException {
        final String addUserWxOpenID = "INSERT INTO sys_user_wxopenid(user_id, open_id, features) VALUES (? ,? ,?)";
        if (!existsPreparedStatement(addUserWxOpenID))
            registeyPreparedStatement(addUserWxOpenID);
        return preparedStatement(addUserWxOpenID);
    }

    public void addUserWxOpenID(long userID, String openID, JSONObject features) throws SQLException {
        addUserWxOpenIDPrepared().setLong(1, userID);
        addUserWxOpenIDPrepared().setString(2, openID);
        addUserWxOpenIDPrepared().setString(3, features.toJSONString());
        addUserWxOpenIDPrepared().execute();
    }

    private PreparedStatement rmUserWxOpenIDPrepared() throws SQLException {
        final String rmUserWxOpenID = "DELETE FROM sys_user_wxopenid WHERE ID = ?";
        if (!existsPreparedStatement(rmUserWxOpenID))
            registeyPreparedStatement(rmUserWxOpenID);
        return preparedStatement(rmUserWxOpenID);
    }

    public void rmUserWxOpenID(String id) throws SQLException {
        rmUserWxOpenIDPrepared().setString(1, id);
        rmUserWxOpenIDPrepared().execute();
    }

    private PreparedStatement fetchWxFeaturesByOpenIDPrepared() throws SQLException {
        final String fetchWxFeaturesByOpenID = "SELECT user_id ,features FROM sys_user_wxopenid WHERE open_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchWxFeaturesByOpenID))
            registeyPreparedStatement(fetchWxFeaturesByOpenID);
        return preparedStatement(fetchWxFeaturesByOpenID);
    }

    public JSONObject fetchWxFeaturesByOpenID(String openID) throws SQLException {
        fetchWxFeaturesByOpenIDPrepared().setString(1, openID);
        ResultSet set = fetchWxFeaturesByOpenIDPrepared().executeQuery();
        if (!set.next())
            return null;
        long userID = set.getLong(1);
        JSONObject jsonObject = JSONObject.parseObject(set.getString(2));
        jsonObject.put("userID", userID);
        return jsonObject;
    }

    private PreparedStatement fetchWxFeaturesByUserIDPrepared() throws SQLException {
        final String fetchWxFeaturesByUserID = "SELECT features FROM sys_user_wxopenid WHERE user_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchWxFeaturesByUserID))
            registeyPreparedStatement(fetchWxFeaturesByUserID);
        return preparedStatement(fetchWxFeaturesByUserID);
    }

    public JSONObject fetchWxFeaturesByUserID(long userID) throws SQLException {
        fetchWxFeaturesByUserIDPrepared().setLong(1, userID);
        ResultSet set = fetchWxFeaturesByUserIDPrepared().executeQuery();
        if (!set.next())
            return null;
        return JSONObject.parseObject(set.getString(1));
    }

    private PreparedStatement upWxFeaturesByUserIDPrepared() throws SQLException {
        final String upWxFeaturesByUserID = "UPDATE sys_user_wxopenid SET features = ? WHERE user_id = ?";
        if (!existsPreparedStatement(upWxFeaturesByUserID))
            registeyPreparedStatement(upWxFeaturesByUserID);
        return preparedStatement(upWxFeaturesByUserID);
    }

    public void upWxFeaturesByUserID(JSONObject features, long userID) throws SQLException {
        upWxFeaturesByUserIDPrepared().setString(1, features.toJSONString());
        upWxFeaturesByUserIDPrepared().setLong(2, userID);
        upWxFeaturesByUserIDPrepared().execute();
    }

    private PreparedStatement fetchUserWxFeaturesCountPrepared() throws SQLException {
        final String fetchUserWxFeaturesCount = "SELECT count(1) FROM sys_user_wxopenid WHERE user_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchUserWxFeaturesCount))
            registeyPreparedStatement(fetchUserWxFeaturesCount);
        return preparedStatement(fetchUserWxFeaturesCount);
    }

    public long fetchUserWxFeaturesCount(long userID) throws SQLException {
        fetchUserWxFeaturesCountPrepared().setLong(1, userID);
        ResultSet set = fetchUserWxFeaturesCountPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("query `fetchUserWxFeaturesCount` faild");
        return set.getLong(1);
    }

    private PreparedStatement fetchUserAuthProjectListPrepared() throws SQLException {
        final String fetchUserAuthProjectList = "select fpi.* from factory_project_user_ref fpur,factory_project_info fpi where fpur.project_id = fpi.fpi_id and user_id = ?";
        if (!existsPreparedStatement(fetchUserAuthProjectList))
            registeyPreparedStatement(fetchUserAuthProjectList);
        return preparedStatement(fetchUserAuthProjectList);
    }

    public List<FactoryProjectInfo> fetchUserAuthProjectList(long userID) throws SQLException {
        fetchUserAuthProjectListPrepared().setLong(1, userID);
        ResultSet set = fetchUserAuthProjectListPrepared().executeQuery();
        List<FactoryProjectInfo> projectList = new ArrayList<>();
        while (set.next())
            projectList.add(new FactoryProjectInfo(set));
        return projectList;
    }
}
