from datetime import datetime

from flask import session
from utils.mysql_helper import MySQLHelper

from models.project_data import ProjectModel, SubProjectModel, SubProjectItemModel


class ProjectStore:

    def __init__(self):
        self._db_helper = MySQLHelper()

    @staticmethod
    def _get_current_user():
        return session.get('username', 'system')

    def filter_data(self, sql:str, params:tuple):
        current_user = self._get_current_user()
        if current_user == 'system' or current_user == 'admin':
            return sql, params
        sql += " AND create_by=%s"
        params += (current_user,)
        return sql, params

    def query_project_all_paginated(self, page: int, per_page: int, keyword: str = None):
        offset = (page - 1) * per_page
        sql_count = "SELECT COUNT(*) as count FROM project WHERE is_del=%s"
        sql = "SELECT id,project_name,description,delete_by,deleted_at,create_by,created_at,update_by,updated_at FROM project WHERE is_del=%s"
        params_count = (0,)
        params = (0,)
        if keyword:
            sql_count += " AND (project_name LIKE %s)"
            sql += " AND (project_name LIKE %s)"
            params_count += (f"%{keyword}%",)
            params += (f"%{keyword}%",)
        sql_count, params_count = self.filter_data(sql_count, params_count)
        sql, params = self.filter_data(sql, params)
        sql += " ORDER BY created_at DESC LIMIT %s OFFSET %s"
        params += (per_page, offset)

        with self._db_helper:
            result_count = self._db_helper.fetch_one(sql_count, params_count)
            count = result_count["count"] if result_count else 0
            result = self._db_helper.execute_query(sql, params)
            data = []
            if not result:
                return data, count
            for item in result:
                data.append(
                    ProjectModel(
                        project_id=item["id"],
                        project_name=item["project_name"],
                        description=item["description"],
                        delete_by=item["delete_by"],
                        deleted_at=item["deleted_at"],
                        create_by=item["create_by"],
                        created_at=item["created_at"],
                        update_by=item["update_by"],
                        updated_at=item["updated_at"],
                    ))
            return data, count

    def query_project_by_id(self, project_id: int) -> ProjectModel | None:
        sql = "SELECT id,project_name,description,delete_by,deleted_at,create_by,created_at,update_by,updated_at FROM project WHERE is_del=0 AND id = %s"
        params = (project_id,)
        with self._db_helper:
            result = self._db_helper.fetch_one(sql, params)
            if not result:
                return None
            return ProjectModel(
                project_id=result["id"],
                project_name=result["project_name"],
                description=result["description"],
                delete_by=result["delete_by"],
                deleted_at=result["deleted_at"],
                create_by=result["create_by"],
                created_at=result["created_at"],
                update_by=result["update_by"],
                updated_at=result["updated_at"],
            )

    def insert_project(self, project_data: ProjectModel):
        current_user = self._get_current_user()
        sql = "INSERT INTO project (project_name,description,create_by,created_at,update_by,updated_at) VALUES (%s,%s,%s,%s,%s,%s)"
        params = (project_data.project_name,project_data.description, current_user, datetime.now(), current_user, datetime.now())
       
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)

    def update_project(self, project_data: ProjectModel):
        current_user = self._get_current_user()
        sql = "UPDATE project SET project_name=%s,description=%s,update_by=%s,updated_at=%s WHERE id=%s"
        params = (project_data.project_name, project_data.description, current_user, datetime.now(), project_data.id)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)

    def delete_project(self, project_id: int):
        current_user = self._get_current_user()
        sql = "UPDATE project SET is_del=1,project.delete_by=%s,deleted_at=%s WHERE id=%s"
        params = (current_user, datetime.now(), project_id)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)

    def insert_sub_project(self, sub_project: SubProjectModel) -> int:
        current_user = self._get_current_user()
        sql = "INSERT INTO sub_project (project_id,sub_project_name,work_catalog,work_content,standard_version,file_paths,created_at,create_by) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)"
        params = (
            sub_project.project_id,
            sub_project.sub_project_name,
            sub_project.work_catalog,
            sub_project.work_content,
            sub_project.standard_version,
            sub_project.file_paths,
            datetime.now(),
            current_user,
        )
        with self._db_helper:
            new_id = self._db_helper.execute_non_query(sql, params)
        self.insert_sub_project_item_list(sub_project)
        return new_id

    def update_sub_project(self, sub_project: SubProjectModel):
        current_user = sub_project.create_by or self._get_current_user()
        sql = "UPDATE sub_project SET sub_project_name = %s, work_catalog = %s, work_content = %s, standard_version = %s ,status = %s,updated_at = %s,update_by = %s WHERE id = %s"
        params = (
            sub_project.sub_project_name,
            sub_project.work_catalog,
            sub_project.work_content,
            sub_project.standard_version,
            sub_project.status,
            datetime.now(),
            current_user,
            sub_project.id,
        )
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)

    def delete_sub_project(self, sub_project_id: int) -> bool:
        current_user = self._get_current_user()
        sql = "UPDATE sub_project SET is_del=1,delete_by=%s,deleted_at=%s WHERE id = %s"
        params = (current_user, datetime.now(), sub_project_id,)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
            return True
    def query_sub_project_all(self):
        sql = "SELECT id,project_id,sub_project_name,work_catalog,work_content,standard_version,status,file_paths,created_at FROM sub_project WHERE is_del=0"
        with self._db_helper:
            data = []
            result = self._db_helper.execute_query(sql)
            if not result:
                return data
            for item in result:
                data.append(
                    SubProjectModel(
                        sub_id=item["id"],
                        project_id=item["project_id"],
                        sub_project_name=item["sub_project_name"],
                        work_catalog=item["work_catalog"],
                        work_content=item["work_content"],
                        standard_version=item["standard_version"],
                        status=item["status"],
                        file_paths=item["file_paths"],
                        created_at=item["created_at"],
                    ))
            return data
    def query_sub_project_all_paginated(self, project_id: int, page: int, per_page: int, keyword: str = None, status: int = None) -> (list[SubProjectModel], None):
        offset = (page - 1) * per_page
        sql_count = "SELECT COUNT(*) as count FROM sub_project WHERE is_del=0 AND project_id=%s"
        sql = "SELECT id,project_id,sub_project_name,work_catalog,work_content,standard_version,status,file_paths,created_at FROM sub_project WHERE is_del=0 AND project_id=%s"
        params_count = (project_id,)
        params =  (project_id,)
        q_1=" AND (sub_project_name LIKE %s)"
        q_2=" AND status=%s"
        if keyword:
            sql_count += q_1
            params_count += (f"%{keyword}%",)
            sql += q_1
            params += (f"%{keyword}%",)

        if status is not None:
            sql_count += q_2
            params_count += (status,)
            sql += q_2
            params += (status,)
        sql_count,params_count= self.filter_data(sql_count,params_count)
        sql,params = self.filter_data(sql,params)
        sql += " ORDER BY status,created_at DESC LIMIT %s OFFSET %s"
        params += (per_page, offset)

        with self._db_helper:
            result_count = self._db_helper.fetch_one(sql_count, params_count)
            count = result_count["count"] if result_count else 0
            result = self._db_helper.execute_query(sql, params)
            data = []
            if not result:
                return [], count
            for item in result:
                data.append(
                    SubProjectModel(
                        sub_id=item["id"],
                        project_id=item["project_id"],
                        sub_project_name=item["sub_project_name"],
                        work_catalog=item["work_catalog"],
                        work_content=item["work_content"],
                        standard_version=item["standard_version"],
                        status=item["status"],
                        file_paths=item["file_paths"],
                        created_at=item["created_at"],
                    ))
        return data, count

    def query_sub_project(self, sub_project_id: int, with_items=False) -> SubProjectModel | None:
        sql = "SELECT id,project_id,sub_project_name,work_catalog,work_content,standard_version,status,file_paths,create_by,created_at FROM sub_project WHERE is_del=0 AND id = %s"
        params = (sub_project_id,)
        sql_items = "SELECT id,project_id,sub_project_id,device_name,device_model,standard_version,standard_no,process_status,process_time,send_status,send_time FROM sub_project_item WHERE sub_project_id = %s"
        with self._db_helper:
            result = self._db_helper.fetch_one(sql, params)
            if not result:
                return None
            data = SubProjectModel(
                        project_id=result["project_id"],
                        sub_project_name=result["sub_project_name"],
                        work_catalog=result["work_catalog"],
                        work_content=result["work_content"],
                        standard_version=result["standard_version"],
                        status=result["status"],
                        file_paths=result["file_paths"],
                        sub_id=result["id"],
                        create_by=result["create_by"],
                        created_at=result["created_at"])
            if not with_items:
                return data
            items_result = self._db_helper.execute_query(sql_items, params)
            if items_result:
                for item in items_result:
                    data.add_item(
                        SubProjectItemModel(
                            item_id=item["id"],
                            project_id=item["project_id"],
                            sub_project_id=item["sub_project_id"],
                            device_name=item["device_name"],
                            device_model=item["device_model"],
                            standard_version=item["standard_version"],
                            standard_no=item["standard_no"],
                            process_status=item["process_status"],
                            process_time=item["process_time"],
                            send_status=item["send_status"],
                            send_time=item["send_time"],
                        ))
            return data
    def query_sub_project_items_by_project_paginated(self, sub_project_id: int, page: int, per_page: int, keyword: str = None, process_status: int = None,send_status: int = None) -> (list[SubProjectItemModel], int):
        offset = (page - 1) * per_page
        sql_count = "SELECT COUNT(*) as count FROM sub_project_item WHERE is_del=0 AND sub_project_id = %s"
        sql = "SELECT id,project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,process_status,process_time,send_status,send_time FROM sub_project_item WHERE is_del=0 AND sub_project_id = %s"
        params_count = (sub_project_id,)
        params = (sub_project_id,)

        if keyword:
            sql_count += " AND (device_name LIKE %s OR device_model LIKE %s)"
            params_count += (f"%{keyword}%", f"%{keyword}%")
            sql += " AND (device_name LIKE %s OR device_model LIKE %s)"
            params += (f"%{keyword}%", f"%{keyword}%")
        if process_status is not None:
            sql_count += " AND process_status=%s"
            params_count += (process_status,)
            sql += " AND process_status=%s"
            params += (process_status,)
        if send_status is not None:
            sql_count += " AND send_status=%s"
            params_count += (send_status,)
            sql += " AND send_status=%s"
            params += (send_status,)
        sql_count, params_count = self.filter_data(sql_count, params_count)
        sql, params = self.filter_data(sql, params)
        sql += " ORDER BY device_name,device_model LIMIT %s OFFSET %s"
        params += (per_page, offset)

        with self._db_helper:
            result_count = self._db_helper.fetch_one(sql_count, params_count)
            count = result_count["count"] if result_count else 0
            result = self._db_helper.execute_query(sql, params)
            data = []
            if not result:
                return data, count
            for item in result:
                data.append(
                    SubProjectItemModel(
                        item_id=item["id"],
                        project_id=item["project_id"],
                        sub_project_id=item["sub_project_id"],
                        device_name=item["device_name"],
                        device_model=item["device_model"],
                        device_unit=item["device_unit"],
                        device_count=item["device_count"],
                        standard_version=item["standard_version"],
                        standard_no=item["standard_no"],
                        process_status=item["process_status"],
                        process_time=item["process_time"],
                        send_status=item["send_status"],
                        send_time=item["send_time"],
                    ))
        return data, count
    def query_sub_project_items_by_project(self, sub_project_id: int, with_empty=True) -> list[SubProjectItemModel]:
        sql = "SELECT id,project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no FROM sub_project_item WHERE sub_project_id = %s"
        sql += "" if with_empty else " AND standard_no !='' AND standard_no IS NOT NULL"
        params = (sub_project_id,)
        with self._db_helper:
            result = self._db_helper.execute_query(sql, params)
            data = []
            if not result:
                return data
            for item in result:
                data.append(
                    SubProjectItemModel(
                        item_id=item["id"],
                        project_id=item["project_id"],
                        sub_project_id=item["sub_project_id"],
                        device_name=item["device_name"],
                        device_model=item["device_model"],
                        device_unit=item["device_unit"],
                        device_count=item["device_count"],
                        standard_version=item["standard_version"],
                        standard_no=item["standard_no"],
                    ))
            return data

    def insert_sub_project_item_list(self, sub_project):
        if len(sub_project.items) <= 0:
            return
        sql = "INSERT INTO sub_project_item (project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,create_by,created_at) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
        params_items = []
        for item in sub_project.items:
            params_items.append((
                sub_project.project_id,
                sub_project.id,
                item.device_name,
                item.device_model,
                item.device_unit,
                item.device_count,
                sub_project.standard_version,
                item.standard_no,
                sub_project.create_by,
                datetime.now(),
            ))
        with self._db_helper:
            self._db_helper.execute_many(sql, params_items)

    def update_sub_project_file_path(self, sub_project_id: int, file_paths: str):
        sql = "UPDATE sub_project SET file_paths = %s WHERE id = %s"
        params = (file_paths, sub_project_id,)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
    def update_sub_project_status(self, sub_project_id:int, status:int):
        sql = "UPDATE sub_project SET status = %s,updated_at = %s WHERE id = %s"
        params = (status, datetime.now(), sub_project_id,)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
    def re_insert_sub_project(self, sub_project: SubProjectModel) -> bool:
        if not sub_project.id:
            return False
        self.update_sub_project(sub_project)
        sql = "DELETE FROM sub_project_item WHERE sub_project_id = %s"
        params = (sub_project.id,)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
        self.insert_sub_project_item_list(sub_project)

    def query_sub_project_item_by_id(self, item_id:int) -> SubProjectItemModel | None:
        sql = "SELECT id,project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,process_status,process_time,send_status,send_time FROM sub_project_item WHERE id = %s"
        params = (item_id,)
        with self._db_helper:
            result = self._db_helper.fetch_one(sql, params)
            if not result:
                return None
            data = SubProjectItemModel(
                item_id=result["id"],
                project_id=result["project_id"],
                sub_project_id=result["project_id"],
                device_name=result["device_name"],
                device_model=result["device_model"],
                device_unit=result["device_unit"],
                device_count=result["device_count"],
                standard_version=result["standard_version"],
                standard_no=result["standard_no"],
                process_status=result["process_status"],
                process_time=result["process_time"],
                send_status=result["send_status"],
                send_time=result["send_time"],
                updated_at=datetime.now()
            )
            return data
    def insert_sub_project_item(self, project_item: SubProjectItemModel):
        current_user = self._get_current_user()
        sql = "INSERT INTO sub_project_item (project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,process_status,send_status,create_by,created_at) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
        params = (
            project_item.project_id,
            project_item.sub_project_id,
            project_item.device_name,
            project_item.device_model,
            project_item.device_unit,
            project_item.device_count,
            project_item.standard_version,
            project_item.standard_no,
            project_item.process_status,
            project_item.send_status,
            current_user,
            datetime.now(),
        )
        with self._db_helper:
           return self._db_helper.execute_non_query(sql, params)
    def update_sub_project_item(self, project_item: SubProjectItemModel) -> bool:
        current_user = self._get_current_user()
        sql = "UPDATE sub_project_item SET device_name= %s,device_model= %s,device_unit= %s,device_count= %s,standard_no = %s,update_by,updated_at = %s WHERE id = %s"
        params = (
            project_item.device_name,
            project_item.device_model,
            project_item.device_unit,
            project_item.device_count,
            project_item.standard_no,
            current_user,
            datetime.now(),
            project_item.id
        )
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
            return True
    def delete_sub_project_item_by_id(self, item_id: int):
        current_user = self._get_current_user()
        sql = "Update sub_project_item SET is_del=1,delete_by=%s,deleted_at=%s WHERE id = %s"
        params = (current_user, datetime.now(),item_id )
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
            return True
    def update_sub_project_item_standard_no(self, item_id:int, standard_no:str):
        sql = "UPDATE sub_project_item SET standard_no=%s,process_status = 2,process_time = %s,updated_at=%s WHERE id = %s"
        params = (standard_no, datetime.now(), datetime.now(), item_id,)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
    def update_sub_project_item_process_status(self, item_id:int, status:int):
        sql = "UPDATE sub_project_item SET process_status = %s,process_time = %s WHERE id = %s"
        params = (status, datetime.now(), item_id,)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
    def update_sub_project_item_send_status(self, item_id:int, status:int):
        sql = "UPDATE sub_project_item SET send_status = %s,send_time = %s WHERE id = %s"
        params = (status, datetime.now(), item_id,)
        with self._db_helper:
            self._db_helper.execute_non_query(sql, params)
