from io import BytesIO, TextIOWrapper
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import HTMLResponse
from starlette import status

from src.depends.services import get_service
from src.logging.get_logger import get_logger
from src.model.internal.session import UserSession
from src.model.request.master_mainte_csvdl import MasterMainteCsvDlModel
from src.model.request.master_mainte_csvup import MasterMainteCsvUpModel
from src.model.view.inst_emp_csv_download_view_model import \
    InstEmpCsvDownloadViewModel
from src.model.view.inst_emp_csv_upload_view_model import \
    InstEmpCsvUploadViewModel
from src.model.view.master_mainte_menu_view_model import \
    MasterMainteMenuViewModel
from src.model.view.table_override_view_model import TableOverrideViewModel
from src.router.session_router import AuthenticatedRoute
from src.services.batch_status_service import BatchStatusService
from src.services.login_service import LoginService
from src.services.master_mainte_service import MasterMainteService
from src.system_var import constants
from src.templates import templates

logger = get_logger('マスターメンテ')

router = APIRouter()
router.route_class = AuthenticatedRoute

#########################
# Views                 #
#########################


@router.get('/masterMainteMenu', response_class=HTMLResponse)
def menu_view(
    request: Request,
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)

    # 画面表示用のモデル
    menu = MasterMainteMenuViewModel()

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'masterMainteMenu.html',
        {
            'request': request,
            'menu': menu
        },
        headers={'session_key': session_key}
    )
    return templates_response


@router.get('/instEmpCsvUL', response_class=HTMLResponse)
def inst_emp_csv_upload_view(
    request: Request,
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)

    # 画面表示用のモデル
    mainte_csv_up = InstEmpCsvUploadViewModel()

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'instEmpCsvUL.html',
        {
            'request': request,
            'mainte_csv_up': mainte_csv_up
        },
        headers={'session_key': session_key}
    )
    return templates_response


@router.post('/instEmpCsvUL', response_class=HTMLResponse)
async def inst_emp_csv_upload(
    request: Request,
    csv_upload_form: MasterMainteCsvUpModel = Depends(MasterMainteCsvUpModel.as_form),
    master_mainte_service: MasterMainteService = Depends(get_service(MasterMainteService)),
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)

    # 画面表示用のモデル
    error_message_list = []
    csv_filename: str = csv_upload_form.csv_file.filename
    if csv_upload_form.csv_file.size == 0:
        error_message_list.append('選択されたファイルが見つかりませんでした。')
    elif not csv_filename.endswith('.csv'):
        error_message_list.append('選択されたファイル形式が"csv"ではありません。')
    elif csv_upload_form.csv_file.size >= constants.MENTE_CSV_UPLOAD_MAX_FILE_SIZE_BYTE:
        error_message_list.append('選択されたCSVファイルサイズが大きいです。20MB未満にしてください。')
    else:
        mainte_csv_up = master_mainte_service.prepare_mainte_csv_up_view(
            TextIOWrapper(BytesIO(await csv_upload_form.csv_file.read()), encoding='utf-8'),
            csv_upload_form.csv_file.filename,
            csv_upload_form)

    if len(error_message_list) > 0:
        mainte_csv_up = InstEmpCsvUploadViewModel(
            is_verified=True,
            error_message_list=error_message_list,
            select_function=csv_upload_form.select_function,
            select_table=csv_upload_form.select_table)

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'instEmpCsvUL.html',
        {
            'request': request,
            'mainte_csv_up': mainte_csv_up
        },
        headers={'session_key': session_key}
    )
    return templates_response


@router.post('/newInst', response_class=HTMLResponse)
def new_inst_result_view(
    request: Request,
    csv_upload_form: Optional[MasterMainteCsvUpModel] = Depends(MasterMainteCsvUpModel.as_form),
    master_mainte_service: MasterMainteService = Depends(get_service(MasterMainteService)),
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService)),
    login_service: LoginService = Depends(get_service(LoginService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)
    # ユーザIDからユーザ名を取得
    user_name = login_service.logged_in_user(session.user_id).user_name
    # CSVデータを登録し、登録完了画面のモデルを返却する
    mainte_csv_up = master_mainte_service.prepare_mainte_new_inst_view(user_name, csv_upload_form)

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'instEmpCsvUL.html',
        {
            'request': request,
            'mainte_csv_up': mainte_csv_up
        },
        headers={'session_key': session_key}
    )
    return templates_response


@ router.get('/instEmpCsvDL', response_class=HTMLResponse)
def inst_emp_csv_download_view(
    request: Request,
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)

    # 画面表示用のモデル
    mainte_csv_dl = InstEmpCsvDownloadViewModel(
        is_search=False
    )

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'instEmpCsvDL.html',
        {
            'request': request,
            'mainte_csv_dl': mainte_csv_dl
        },
        headers={'session_key': session_key}
    )
    return templates_response


@router.post('/download', response_class=HTMLResponse)
def inst_emp_csv_download(
    request: Request,
    csv_download_form: Optional[MasterMainteCsvDlModel] = Depends(MasterMainteCsvDlModel.as_form),
    master_mainte_service: MasterMainteService = Depends(get_service(MasterMainteService)),
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)

    search_result_df = master_mainte_service.search_emp_chg_inst_data(csv_download_form)

    (result_msg, download_file_url) = master_mainte_service.upload_emp_chg_inst_data_file(
        search_result_df,
        session.user_id,
        csv_download_form.select_table)

    # 画面表示用のモデル
    mainte_csv_dl = InstEmpCsvDownloadViewModel(
        is_search=True,
        ta_cd=csv_download_form.ta_cd,
        inst_cd=csv_download_form.inst_cd,
        emp_cd=csv_download_form.emp_cd,
        apply_date_from=csv_download_form.apply_date_from,
        start_date_from=csv_download_form.start_date_from,
        start_date_to=csv_download_form.start_date_to,
        end_date_from=csv_download_form.end_date_from,
        end_date_to=csv_download_form.end_date_to,
        create_date_from=csv_download_form.create_date_from,
        create_date_to=csv_download_form.create_date_to,
        update_date_from=csv_download_form.update_date_from,
        update_date_to=csv_download_form.update_date_to,
        select_table=csv_download_form.select_table,
        data_count=search_result_df.shape[0],
        download_file_url=download_file_url,
        file_name=constants.MENTE_CSV_DOWNLOAD_FILE_NAME,
        result_msg=result_msg
    )

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'instEmpCsvDL.html',
        {
            'request': request,
            'mainte_csv_dl': mainte_csv_dl
        },
        headers={'session_key': session_key}
    )
    return templates_response


@router.get('/tableOverride', response_class=HTMLResponse)
def table_override_view(
    request: Request,
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)

    # 画面表示用のモデル
    table_override = TableOverrideViewModel()

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'tableOverride.html',
        {
            'request': request,
            'table_override': table_override
        },
        headers={'session_key': session_key}
    )
    return templates_response


@router.post('/tableOverride', response_class=HTMLResponse)
def table_override_result_view(
    request: Request,
    master_mainte_service: MasterMainteService = Depends(get_service(MasterMainteService)),
    batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
):
    session: UserSession = request.session

    # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる
    if session.master_mainte_flg == constants.PERMISSION_DISABLED:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)

    # バッチ処理中の場合、ログアウトさせる
    if batch_status_service.is_batch_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
                            detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE)
    # dump処理中の場合、ログアウトさせる
    if batch_status_service.is_dump_processing():
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)

    # 画面表示用のモデル
    table_override = master_mainte_service.copy_data_real_to_dummy()

    # レスポンス
    session_key = session.session_key
    templates_response = templates.TemplateResponse(
        'tableOverride.html',
        {
            'request': request,
            'table_override': table_override
        },
        headers={'session_key': session_key}
    )
    return templates_response
