from src.batch.ultmarc.utmp_tables.table_mapper.ultmarc_table_mapper import \
    UltmarcTableMapper
from src.batch.ultmarc.utmp_tables.tables.com_dr_wrkplace import ComDrWrkplace


class ComDrWrkplaceMapper(UltmarcTableMapper):
    """レイアウト区分502:COM_医師勤務先 登録処理"""

    # レコード存在確認SQL
    RECORD_EXISTS_QUERY = """\
    SELECT
        COUNT(*) AS count_num
    FROM
        src05.com_dr_wrkplace
    WHERE
            dcf_pcf_dr_cd = :full_dcfdr_code
        AND dcf_dsf_inst_cd = :full_hp_code
    """
    # COM_所属部課から所属部科カナと所属部科名を取得するSQL
    GET_NAME_FROM_COM_BLNG_SEC_QUERY = """\
    SELECT
        blng_sec_kana,
        blng_sec_name
    FROM
        src05.com_blng_sec
    WHERE
        blng_sec_cd = :sectcode
    """
    # データ登録用SQL
    INSERT_QUERY = """\
    INSERT INTO src05.com_dr_wrkplace (
        dcf_dsf_inst_cd,
        dcf_pcf_dr_cd,
        blng_sec_cd,
        post_cd,
        identity_cd,
        aply_start_ymd,
        blng_sec_name_kana,
        blng_sec_name,
        notdm_flg,
        regist_ymd,
        sys_regist_date,
        regist_prgm_id,
        sys_update_date,
        update_prgm_id
    )
    VALUES (
        :full_hp_code,
        :full_dcfdr_code,
        :sectcode,
        :postcode,
        :identitycode,
        :syor_date,
        :sectname_kana,
        :sectname,
        :notdm_flg,
        :execute_date_str_ymd,
        :execute_datetime,
        :program_name,
        :execute_datetime,
        :program_name
    )
    """

    # 更新用SQL
    UPDATE_QUERY = """\
    UPDATE src05.com_dr_wrkplace
    SET
        {update_columns}
        update_ymd = :execute_date_str_ymd,
        sys_update_date = :execute_datetime,
        update_prgm_id = :program_name
    WHERE
            DCF_PCF_DR_CD= :full_dcfdr_code
        AND DCF_DSF_INST_CD = :full_hp_code
    """

    # 更新・削除の場合に該当のデータを履歴テーブルに退避するSQL
    TO_HISTORY_QUERY = """\
    INSERT INTO src05.com_dr_wrkplace_his (
        dcf_dsf_inst_cd,
        dcf_pcf_dr_cd,
        blng_sec_cd,
        post_cd,
        identity_cd,
        aply_start_ymd,
        blng_sec_name_kana,
        blng_sec_name,
        notdm_flg,
        aply_end_ymd,
        regist_ymd,
        sys_regist_date,
        regist_prgm_id,
        sys_update_date,
        update_prgm_id
    )
    SELECT
        dcf_dsf_inst_cd,
        dcf_pcf_dr_cd,
        (
            CASE
                WHEN blng_sec_cd = '' THEN '9999'
                ELSE blng_sec_cd
            END
        ) AS blng_sec_cd,
        (
            CASE
                WHEN post_cd = '' THEN '999'
                ELSE post_cd
            END
        ) AS post_cd,
        (
            CASE
                WHEN identity_cd = '' THEN '999'
                ELSE identity_cd
            END
        ) AS identity_cd,
        DATE_FORMAT(aply_start_ymd, '%Y%m%d'),
        blng_sec_name_kana,
        blng_sec_name,
        notdm_flg,
        (
            CASE
                WHEN DATE_FORMAT(aply_start_ymd, '%Y%m%d') > DATE_FORMAT(:syor_date, '%Y%m%d') -1 THEN DATE_FORMAT(aply_start_ymd, '%Y%m%d')
                ELSE DATE_FORMAT(:syor_date, '%Y%m%d') -1
            END
        ) AS aply_end_ymd,
        :execute_date_str_ymd,
        :execute_datetime,
        :program_name,
        :execute_datetime,
        :program_name
    FROM
        src05.com_dr_wrkplace
    WHERE
            dcf_pcf_dr_cd = :full_dcfdr_code
        AND dcf_dsf_inst_cd = :full_hp_code
        AND aply_start_ymd < :syor_date
    """

    # 退職レコードの場合、物理削除するSQL
    PHYSICAL_DELETE_FOR_RETIREMENT_QUERY = """\
    DELETE FROM src05.com_dr_wrkplace
    WHERE
            dcf_pcf_dr_cd = :full_dcfdr_code
        AND dcf_dsf_inst_cd = :full_hp_code
    """

    record: ComDrWrkplace

    def __init__(self, record: list[str], db) -> None:
        super().__init__(record, db, ComDrWrkplace)
        program_name = __name__.split('.')[-1]  # 当モジュール名(現行から変わっている)
        # モジュール名をクエリパラメータに設定
        self.query_parameter['program_name'] = program_name
        # 読み込んだレコード値もクエリパラメータに追加
        self.query_parameter = {**self.query_parameter, **self.record.to_sql_parameter()}

    def make_query(self):
        # 所属部科を取得し、所属部科カナと所属部科名を設定する
        self.__set_sect_name_and_sect_name_kana()
        # 追加/更新クエリを生成
        # 履歴へのレコード登録もあるため、リストで返る
        self.queries = self.__make_queries()
        return

    def __set_sect_name_and_sect_name_kana(self):
        # 所属部科を取得し、所属部科カナと所属部科名を設定する
        com_blng_sec_records = self.db.execute_select(self.GET_NAME_FROM_COM_BLNG_SEC_QUERY, self.query_parameter)
        if len(com_blng_sec_records) == 0:
            return
        # 必ず1件
        com_blng_sec_record = com_blng_sec_records[0]
        if com_blng_sec_record['blng_sec_kana'] != '' and com_blng_sec_record['blng_sec_kana'] is not None:
            self.record.sectname_kana = com_blng_sec_record['blng_sec_kana']
            self.query_parameter['sectname_kana'] = com_blng_sec_record['blng_sec_kana']

        if com_blng_sec_record['blng_sec_name'] != '' and com_blng_sec_record['blng_sec_name'] is not None:
            self.record.sectname = com_blng_sec_record['blng_sec_name']
            self.query_parameter['sectname'] = com_blng_sec_record['blng_sec_name']

    def __make_queries(self):
        # レコードの存在確認
        record_count = self.db.execute_select(self.RECORD_EXISTS_QUERY, self.query_parameter)
        # 存在しない場合はInsert
        if record_count[0]['count_num'] == 0:
            return [self.INSERT_QUERY]

        # 存在する場合はUpdate
        # 予備/退職異動区分が1(削除：退職)の場合、退職済みのレコードとして処理
        if self.record.drretflag == '1':
            # 履歴への移動と、退職レコードの物理削除
            return [self.TO_HISTORY_QUERY, self.PHYSICAL_DELETE_FOR_RETIREMENT_QUERY]

        # 履歴への移動＋更新クエリ生成
        return self.__make_update_query()

    def __make_update_query(self):
        make_history_query = None
        # 履歴レコード作成判断となる、UPDATE SET句を作成
        set_clauses_with_historical = self.__make_update_columns_with_historical()
        # 履歴レコード作成判断とならない、UPDATE SET句
        set_clause_without_historical = []
        # DM不可フラグの値をセット
        # 履歴レコード作成判断とならないため、後から設定
        if self.record.notdm_flg != '':
            notdm_flg = None if self.record.notdm_flg == '@' else self.record.notdm_flg
            self.query_parameter['notdm_flg'] = notdm_flg
            set_clause_without_historical.append(f'notdm_flg = :notdm_flg')
        # 何かしら更新がある場合、履歴作成クエリを作成
        if len(set_clauses_with_historical) != 0:
            make_history_query = self.TO_HISTORY_QUERY

        update_columns = ','.join(set_clauses_with_historical + set_clause_without_historical)
        if len(update_columns) == 0:
            update_query = None
        else:
            # 何かしら更新がある場合、末尾にカンマを付けてSET句を完成させる
            update_columns += ','
            update_query = self.UPDATE_QUERY.format(
                update_columns=update_columns
            )

        return [make_history_query, update_query]

    def __make_update_columns_with_historical(self):
        # 履歴レコードの作成有無を判断するカラムの更新設定
        # DM不可フラグは、履歴レコードの作成判断に使わないため、この関数の外で判定する
        set_clauses = []
        # 役職コード
        if self.record.postcode != '':
            set_clauses.append('post_cd = :postcode')
            self.query_parameter['postcode'] = '' if self.record.postcode == '@' else self.record.postcode
        # 大学順位
        if self.record.identitycode != '':
            set_clauses.append('identity_cd = :identitycode')
            self.query_parameter['identitycode'] = '' if self.record.identitycode == '@' else self.record.identitycode
        # 所属部科(集合項目)
        if self.record.sectcode != '':
            # 所属部科コード
            self.query_parameter['sectcode'] = '9999' if self.record.sectcode == '@' else self.record.sectcode
            set_clauses.append('blng_sec_cd = :sectcode')
            # 所属部科(ｶﾅ)
            sectname_kana = None if self.record.sectname_kana == '@' else self.record.sectname_kana
            self.query_parameter['sectname_kana'] = sectname_kana
            set_clauses.append(f'blng_sec_name_kana = :sectname_kana')
            # 所属部科(漢字)
            # 全角文字なので、修正項目として全角＠が連携されるパターンがある
            sectname = None if self.record.sectname == '＠' else self.record.sectname
            self.query_parameter['sectname'] = sectname
            set_clauses.append(f'blng_sec_name = :sectname')

        # 何かしら更新がある場合、適用開始日をセットする
        if len(set_clauses) != 0:
            # 処理日はパラメータに設定済み
            set_clauses.append("aply_start_ymd = DATE_FORMAT(:syor_date, '%Y%m%d')")

        return set_clauses
