from src.batch.batch_functions import logging_sql
from src.batch.common.batch_context import BatchContext
from src.db.database import Database
from src.error.exceptions import BatchOperationException
from src.logging.get_logger import get_logger
from src.time.elapsed_time import ElapsedTime

batch_context = BatchContext.get_instance()
logger = get_logger('生物由来卸販売ロット分解')


def exec():
    """生物由来卸販売ロット分解"""
    logger.debug('生物由来卸販売ロット分解処理開始')

    # 営業日ではない場合、処理をスキップする
    if batch_context.is_not_business_day:
        logger.info('営業日ではないため、生物由来卸販売ロット分解処理をスキップします。')
        return
    db = Database.get_instance()
    try:
        db.connect()
        db.begin()
        # 生物由来ロット分解データの未確定データを削除する
        _delete_not_confirm_data_in_bio_sales_lot(db)
        # 生物由来ロット分解データを作成する
        _insert_bio_sales_lot(db)
        # 生物由来ロット分解データの不要レコードを削除する
        _delete_empty_lot_record(db)
        # MDB変換マスタビュー（生物由来ロット分解処理用）、メルク施設マスタから施設情報を生物由来ロット分解データにセットする
        _set_inst_info_from_mdb_or_mst_inst(db)
        # V製品マスタから製品情報を生物由来ロット分解データにセットする
        _set_prd_info_from_v_prd_mst(db)
        # 製造ロット管理番号マスタから有効期限を生物由来ロット分解データにセットする
        _set_expr_dt_from_lot_num_mst(db)
        db.commit()
        logger.debug('生物由来卸販売ロット分解処理終了')
        return
    except Exception as e:
        db.rollback()
        raise BatchOperationException(e)
    finally:
        db.disconnect()


def _delete_not_confirm_data_in_bio_sales_lot(db: Database):
    logger.debug('生物由来ロット分解データの未確定データ削除開始')
    try:
        elapsed_time = ElapsedTime()
        sql = """
        DELETE lot FROM src05.bio_sales_lot AS lot
        INNER JOIN src05.bio_sales AS bio
         ON  bio.slip_mgt_num = lot.slip_mgt_num
         AND DATE(bio.dwh_upd_dt) = src05.get_syor_date()
        """
        res = db.execute(sql)
        logging_sql(logger, sql)
        logger.info(f'Query OK, {res.rowcount} rows affected ({elapsed_time.of})')
    except Exception as e:
        logger.debug('生物由来ロット分解データの未確定データ削除に失敗')
        raise e
    logger.debug('生物由来ロット分解データの未確定データ削除に成功')


def _insert_bio_sales_lot(db: Database):
    logger.debug('生物由来ロット分解データの作成開始')
    try:
        elapsed_time = ElapsedTime()
        sql = """
        INSERT INTO src05.bio_sales_lot
        SELECT
            bio.slip_mgt_num AS slip_mgt_num,
            conv.conv_cd AS conv_cd,
            bio.rec_whs_cd AS rec_whs_cd,
            bio.rec_whs_sub_cd AS rec_whs_sub_cd,
            bio.rec_whs_org_cd AS rec_whs_org_cd,
            bio.rec_comm_cd AS rec_comm_cd,
            bio.rec_tran_kbn AS rec_tran_kbn,
            bio.rev_hsdnymd_srk AS rev_hsdnymd_srk,
            bio.rec_urag_num AS rec_urag_num,
            bio.rec_comm_name AS rec_comm_name,
            bio.rec_nonyu_fcl_name AS rec_nonyu_fcl_name,
            bio.rec_nonyu_fcl_addr AS rec_nonyu_fcl_addr,
            -- 3レコードに分解する
            CASE conv.conv_cd
                WHEN 1 THEN bio.rec_lot_num1
                WHEN 2 THEN bio.rec_lot_num2
                WHEN 3 THEN bio.rec_lot_num3
            END AS rec_lot_num,
            bio.rec_ymd AS rec_ymd,
            bio.v_tran_cd AS v_tran_cd,
            bio.tran_kbn_name AS tran_kbn_name,
            bio.whs_org_cd AS whs_org_cd,
            bio.v_whsorg_cd AS v_whsorg_cd,
            bio.whs_org_name AS whs_org_name,
            bio.v_whs_cd AS v_whs_cd,
            bio.whs_name AS whs_name,
            bio.nonyu_fcl_cd AS nonyu_fcl_cd,
            bio.v_inst_cd AS v_inst_cd,
            bio.v_inst_kn AS v_inst_kn,
            bio.v_inst_name AS v_inst_name,
            bio.v_inst_addr AS v_inst_addr,
            bio.comm_cd AS comm_cd,
            bio.product_name AS product_name,
            bio.whs_rep_comm_name AS whs_rep_comm_name,
            bio.whs_rep_nonyu_fcl_name AS whs_rep_nonyu_fcl_name,
            bio.whs_rep_nonyu_fcl_addr AS whs_rep_nonyu_fcl_addr,
            /* 製品名と製品コードは後ほどV製品マスタからセットする */
            -- 製品名
            NULL AS mkr_inf_1,
            -- 製品コード
            NULL AS mkr_cd,
            -- 数量
            -- Veeva取引区分の先頭が「2」の場合、マイナス表示にする
            CASE conv.conv_cd
                WHEN 1 THEN
                    CASE
                        WHEN (LEFT(bio.v_tran_cd, 1) = 2 AND bio.qty1 >= 1) THEN -bio.qty1
                        ELSE bio.qty1
                    END
                WHEN 2 THEN
                    CASE
                        WHEN (LEFT(bio.v_tran_cd, 1) = 2 AND bio.qty2 >= 1) THEN -bio.qty2
                        ELSE bio.qty2
                    END
                WHEN 3 THEN
                    CASE
                        WHEN (LEFT(bio.v_tran_cd, 1) = 2 AND bio.qty3 >= 1) THEN -bio.qty3
                        ELSE bio.qty3
                    END
            END AS qty,
            bio.slip_org_kbn AS slip_org_kbn,
            bio.bef_slip_mgt_num AS bef_slip_mgt_num,
            CASE conv.conv_cd
                WHEN 1 THEN bio.err_flg11
                WHEN 2 THEN bio.err_flg12
                WHEN 3 THEN bio.err_flg13
            END AS lot_no_err_flg,
            CASE bio.err_flg20
                WHEN 'M' THEN '*'
                ELSE NULL
            END AS iko_flg,
            CASE bio.rec_sts_kbn
                WHEN '0' THEN bio.rec_sts_kbn
                WHEN '1' THEN
                    CASE conv.conv_cd
                        WHEN 1 THEN bio.err_flg11
                        WHEN 2 THEN bio.err_flg12
                        WHEN 3 THEN bio.err_flg13
                    END
            END AS rec_sts_kbn,
            CASE
                WHEN bio.bef_slip_mgt_num IS NOT NULL THEN bio.ins_dt
                ELSE NULL
            END AS ins_dt,
            CASE
                WHEN bio.bef_slip_mgt_num IS NOT NULL THEN bio.ins_usr
                ELSE NULL
            END AS ins_usr,
            bio.dwh_upd_dt AS dwh_upd_dt,
            /* 施設情報は後ほどセットする */
            -- 施設コード
            NULL AS inst_cd,
            -- 正式施設名（漢字）
            NULL AS inst_name_form,
            -- 施設住所
            NULL AS address,
            -- 施設電話番号
            NULL AS tel_num,
            CASE conv.conv_cd
                WHEN 1 THEN
                    CASE bio.err_flg11
                        WHEN '0' THEN '正常'
                        WHEN '1' THEN 'ロットエラー'
                        WHEN '2' THEN 'ロットエラー'
                        WHEN '3' THEN 'エラー（解消済）'
                        WHEN '4' THEN 'ロット不明'
                        WHEN '5' THEN 'エラー（解消済）'
                        WHEN '6' THEN 'ロット不明'
                        WHEN '7' THEN '除外'
                        WHEN '8' THEN '除外'
                        WHEN 'Z' THEN '除外'
                    END
                WHEN 2 THEN
                    CASE bio.err_flg12
                        WHEN '0' THEN '正常'
                        WHEN '1' THEN 'ロットエラー'
                        WHEN '2' THEN 'ロットエラー'
                        WHEN '3' THEN 'エラー（解消済）'
                        WHEN '4' THEN 'ロット不明'
                        WHEN '5' THEN 'エラー（解消済）'
                        WHEN '6' THEN 'ロット不明'
                        WHEN '7' THEN '除外'
                        WHEN '8' THEN '除外'
                        WHEN 'Z' THEN '除外'
                    END
                WHEN 3 THEN
                    CASE bio.err_flg13
                        WHEN '0' THEN '正常'
                        WHEN '1' THEN 'ロットエラー'
                        WHEN '2' THEN 'ロットエラー'
                        WHEN '3' THEN 'エラー（解消済）'
                        WHEN '4' THEN 'ロット不明'
                        WHEN '5' THEN 'エラー（解消済）'
                        WHEN '6' THEN 'ロット不明'
                        WHEN '7' THEN '除外'
                        WHEN '8' THEN '除外'
                        WHEN 'Z' THEN '除外'
                    END
            END AS data_kbn,
            CASE bio.slip_org_kbn
                WHEN 'J' THEN 'JD-NET'
                WHEN 'N' THEN 'NHI'
                WHEN 'H' THEN '手入力'
            END AS data_kind,
            CASE conv.conv_cd
                WHEN 1 THEN
                    CASE bio.err_flg11
                        WHEN '0' THEN '正常'
                        WHEN '1' THEN 'ロットエラー'
                        WHEN '2' THEN '日付エラー'
                        WHEN '3' THEN 'ロットエラー（解消済）'
                        WHEN '4' THEN 'ロットエラー（調査不能）'
                        WHEN '5' THEN '日付エラー（解消済）'
                        WHEN '6' THEN '日付エラー（調査不能）'
                        WHEN '7' THEN '除外（卸都合）'
                        WHEN '8' THEN '除外（再送信）'
                        WHEN 'Z' THEN '過去データ'
                    END
                WHEN 2 THEN
                    CASE bio.err_flg12
                        WHEN '0' THEN '正常'
                        WHEN '1' THEN 'ロットエラー'
                        WHEN '2' THEN '日付エラー'
                        WHEN '3' THEN 'ロットエラー（解消済）'
                        WHEN '4' THEN 'ロットエラー（調査不能）'
                        WHEN '5' THEN '日付エラー（解消済）'
                        WHEN '6' THEN '日付エラー（調査不能）'
                        WHEN '7' THEN '除外（卸都合）'
                        WHEN '8' THEN '除外（再送信）'
                        WHEN 'Z' THEN '過去データ'
                    END
                WHEN 3 THEN
                    CASE bio.err_flg13
                        WHEN '0' THEN '正常'
                        WHEN '1' THEN 'ロットエラー'
                        WHEN '2' THEN '日付エラー'
                        WHEN '3' THEN 'ロットエラー（解消済）'
                        WHEN '4' THEN 'ロットエラー（調査不能）'
                        WHEN '5' THEN '日付エラー（解消済）'
                        WHEN '6' THEN '日付エラー（調査不能）'
                        WHEN '7' THEN '除外（卸都合）'
                        WHEN '8' THEN '除外（再送信）'
                        WHEN 'Z' THEN '過去データ'
                    END
            END AS err_dtl_kind,
            NULL AS expr_dt
        FROM
            src05.bio_sales bio
        -- 生物由来変換マスタ
        CROSS JOIN src05.bio_conv conv
        WHERE
                bio.err_flg1 = '0'
            AND bio.err_flg2 = '0'
            AND bio.err_flg3 = '0'
            AND bio.err_flg4 = '0'
            AND bio.err_flg5 = '0'
            AND bio.err_flg6 = '0'
            AND bio.err_flg7 = '0'
            AND bio.err_flg8 = '0'
            AND bio.err_flg9 = '0'
            AND bio.err_flg10 = '0'
            AND bio.rec_sts_kbn <> '99'
            AND DATE(bio.dwh_upd_dt) = src05.get_syor_date()
        """
        res = db.execute(sql)
        logging_sql(logger, sql)
        logger.info(f'Query OK, {res.rowcount} rows affected ({elapsed_time.of})')
    except Exception as e:
        logger.debug('生物由来ロット分解データの作成に失敗')
        raise e
    logger.debug('生物由来ロット分解データの作成に成功')


def _delete_empty_lot_record(db: Database):
    logger.debug('生物由来ロット分解データの製造番号が空のレコードを削除開始')
    try:
        elapsed_time = ElapsedTime()
        sql = """
        DELETE FROM src05.bio_sales_lot lot
        WHERE
            -- 空白15桁のデータはロット情報が空とみなして削除する
            lot.rec_lot_num = REPEAT(' ', 15) OR lot.rec_lot_num IS NULL
        """
        res = db.execute(sql)
        logging_sql(logger, sql)
        logger.info(f'Query OK, {res.rowcount} rows affected ({elapsed_time.of})')
    except Exception as e:
        logger.debug('生物由来ロット分解データの製造番号が空のレコードを削除に失敗')
        raise e
    logger.debug('生物由来ロット分解データの製造番号が空のレコードを削除に成功')


def _set_inst_info_from_mdb_or_mst_inst(db: Database):
    logger.debug('MDB変換マスタビュー（生物由来ロット分解処理用）、メルク施設マスタから施設情報を生物由来ロット分解データにセット開始')
    try:
        elapsed_time = ElapsedTime()
        sql = """
        UPDATE
            src05.bio_sales_lot bio
        LEFT OUTER JOIN internal05.view_mdb_cnv_mst mdb
         ON bio.v_inst_cd = mdb.hco_vid_v
        LEFT OUTER JOIN src05.mst_inst inst
         ON bio.v_inst_cd = inst.inst_cd
        SET
            -- 施設コード
            bio.inst_cd = (
                CASE
                    WHEN mdb.mdb_cd IS NOT NULL THEN mdb.mdb_cd
                    ELSE bio.v_inst_cd
                END
            ),
            -- 正式施設名（漢字）
            bio.inst_name_form = (
                CASE
                    WHEN mdb.mdb_cd IS NOT NULL THEN mdb.inst_name_form
                    ELSE inst.inst_name_form
                END
            ),
            -- 施設住所
            bio.address = (
                CASE
                    WHEN mdb.mdb_cd IS NOT NULL THEN mdb.address
                    ELSE inst.address
                END
            ),
            -- 施設電話番号
            bio.tel_num = (
                CASE
                    WHEN mdb.mdb_cd IS NOT NULL THEN mdb.tel_num
                    ELSE inst.tel_num
                END
            )
        """
        res = db.execute(sql)
        logging_sql(logger, sql)
        logger.info(f'Query OK, {res.rowcount} rows affected ({elapsed_time.of})')
    except Exception as e:
        logger.debug('MDB変換マスタビュー（生物由来ロット分解処理用）、メルク施設マスタから施設情報を生物由来ロット分解データにセットに失敗')
        raise e
    logger.debug('MDB変換マスタビュー（生物由来ロット分解処理用）、メルク施設マスタから施設情報を生物由来ロット分解データにセットに成功')


def _set_prd_info_from_v_prd_mst(db: Database):
    logger.debug('V製品マスタから製品情報を生物由来ロット分解データにセット開始')
    try:
        elapsed_time = ElapsedTime()
        sql = """
        UPDATE
            src05.bio_sales_lot bio
        LEFT OUTER JOIN src05.phm_prd_mst_v prd
         ON  bio.comm_cd = prd.prd_cd
         AND STR_TO_DATE(bio.rev_hsdnymd_srk,'%Y%m%d') BETWEEN prd.start_date AND prd.end_date
         AND prd.rec_sts_kbn <> '9'
        SET
            bio.mkr_inf_1 = prd.mkr_inf_1,
            bio.mkr_cd = prd.mkr_cd
        """
        res = db.execute(sql)
        logging_sql(logger, sql)
        logger.info(f'Query OK, {res.rowcount} rows affected ({elapsed_time.of})')
    except Exception as e:
        logger.debug('V製品マスタから製品情報を生物由来ロット分解データにセットに失敗')
        raise e
    logger.debug('V製品マスタから製品情報を生物由来ロット分解データにセットに成功')


def _set_expr_dt_from_lot_num_mst(db: Database):
    # 製造ロット管理番号マスタから有効期限をセット
    logger.debug('製造ロット管理番号マスタから有効期限をセット開始')
    try:
        elapsed_time = ElapsedTime()
        sql = """
        UPDATE
            src05.bio_sales_lot bio
        LEFT OUTER JOIN src05.lot_num_mst lot
         ON  bio.mkr_cd = lot.ser_num
         AND bio.rec_lot_num = lot.lot_num
        SET
            bio.expr_dt = lot.expr_dt
        """
        res = db.execute(sql)
        logging_sql(logger, sql)
        logger.info(f'Query OK, {res.rowcount} rows affected ({elapsed_time.of})')
    except Exception as e:
        logger.debug('製造ロット管理番号マスタから有効期限をセットに失敗')
        raise e
    logger.debug('製造ロット管理番号マスタから有効期限をセットに成功')
