import os
from datetime import datetime
from typing import Annotated, Literal

import aiofiles
from fastapi import File, Form, Path, Query, Request, Response, UploadFile
from fastapi.responses import StreamingResponse
from pydantic_validation_decorator import ValidateFields
from sqlalchemy import ColumnElement
from sqlalchemy.ext.asyncio import AsyncSession

from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitBypassConfig, ApiRateLimitPreset
from common.aspect.data_scope import DataScopeDependency
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, DynamicResponseModel, PageResponseModel, ResponseBaseModel
from config.env import UploadConfig
from module_admin.entity.do.dept_do import SysDept
from module_admin.entity.do.user_do import SysUser
from module_admin.entity.vo.dept_vo import DeptModel, DeptTreeModel
from module_admin.entity.vo.user_vo import (
    AddUserModel,
    AvatarModel,
    CrudUserRoleModel,
    CurrentUserModel,
    DeleteUserModel,
    EditUserModel,
    ResetPasswordModel,
    ResetUserModel,
    UserDetailModel,
    UserInfoModel,
    UserModel,
    UserPageQueryModel,
    UserProfileModel,
    UserRoleQueryModel,
    UserRoleResponseModel,
    UserRowModel,
)
from module_admin.service.dept_service import DeptService
from module_admin.service.role_service import RoleService
from module_admin.service.user_service import UserService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.pwd_util import PwdUtil
from utils.response_util import ResponseUtil
from utils.upload_util import UploadUtil

user_controller = APIRouterPro(
    prefix='/system/user', order_num=3, tags=['系统管理-用户管理'], dependencies=[PreAuthDependency()]
)


@user_controller.get(
    '/deptTree',
    summary='获取部门树接口',
    description='用于获取当前登录用户可见的部门树',
    response_model=DataResponseModel[list[DeptTreeModel]],
    dependencies=[UserInterfaceAuthDependency('system:user:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_DEPT_TREE)
async def get_system_dept_tree(
    request: Request,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
    dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(), data_scope_sql)
    logger.info('获取成功')

    return ResponseUtil.success(data=dept_query_result)


@user_controller.get(
    '/list',
    summary='获取用户分页列表接口',
    description='用于获取用户分页列表',
    response_model=PageResponseModel[UserRowModel],
    dependencies=[UserInterfaceAuthDependency('system:user:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_LIST)
async def get_system_user_list(
    request: Request,
    user_page_query: Annotated[UserPageQueryModel, Query()],
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
    # 获取分页数据
    user_page_query_result = await UserService.get_user_list_services(
        query_db, user_page_query, data_scope_sql, is_page=True
    )
    logger.info('获取成功')

    return ResponseUtil.success(model_content=user_page_query_result)


@user_controller.post(
    '',
    summary='新增用户接口',
    description='用于新增用户',
    response_model=ResponseBaseModel,
    dependencies=[UserInterfaceAuthDependency('system:user:add')],
)
@ValidateFields(validate_model='add_user')
@ApiCacheEvict(namespaces=ApiGroup.USER_ENTITY_MUTATION)
@Log(title='用户管理', business_type=BusinessType.INSERT)
async def add_system_user(
    request: Request,
    add_user: AddUserModel,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    dept_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
    role_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
    if not current_user.user.admin:
        await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql)
        await RoleService.check_role_data_scope_services(
            query_db, ','.join([str(item) for item in add_user.role_ids]), role_data_scope_sql
        )
    add_user.password = PwdUtil.get_password_hash(add_user.password)
    add_user.create_by = current_user.user.user_name
    add_user.create_time = datetime.now()
    add_user.update_by = current_user.user.user_name
    add_user.update_time = datetime.now()
    add_user_result = await UserService.add_user_services(query_db, add_user)
    logger.info(add_user_result.message)

    return ResponseUtil.success(msg=add_user_result.message)


@user_controller.put(
    '',
    summary='编辑用户接口',
    description='用于编辑用户',
    response_model=ResponseBaseModel,
    dependencies=[UserInterfaceAuthDependency('system:user:edit')],
)
@ValidateFields(validate_model='edit_user')
@ApiCacheEvict(namespaces=ApiGroup.USER_PERMISSION_MUTATION)
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def edit_system_user(
    request: Request,
    edit_user: EditUserModel,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    user_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
    dept_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
    role_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
    await UserService.check_user_allowed_services(edit_user)
    if not current_user.user.admin:
        await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql)
        await DeptService.check_dept_data_scope_services(query_db, edit_user.dept_id, dept_data_scope_sql)
        await RoleService.check_role_data_scope_services(
            query_db, ','.join([str(item) for item in edit_user.role_ids]), role_data_scope_sql
        )
    edit_user.update_by = current_user.user.user_name
    edit_user.update_time = datetime.now()
    edit_user_result = await UserService.edit_user_services(query_db, edit_user)
    logger.info(edit_user_result.message)

    return ResponseUtil.success(msg=edit_user_result.message)


@user_controller.delete(
    '/{user_ids}',
    summary='删除用户接口',
    description='用于删除用户',
    response_model=ResponseBaseModel,
    dependencies=[UserInterfaceAuthDependency('system:user:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_ENTITY_MUTATION)
@Log(title='用户管理', business_type=BusinessType.DELETE)
async def delete_system_user(
    request: Request,
    user_ids: Annotated[str, Path(description='需要删除的用户ID')],
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
    user_id_list = user_ids.split(',') if user_ids else []
    if user_id_list:
        if current_user.user.user_id in list(map(int, user_id_list)):
            logger.warning('当前登录用户不能删除')

            return ResponseUtil.failure(msg='当前登录用户不能删除')
        for user_id in user_id_list:
            await UserService.check_user_allowed_services(UserModel(userId=int(user_id)))
            if not current_user.user.admin:
                await UserService.check_user_data_scope_services(query_db, int(user_id), data_scope_sql)
    delete_user = DeleteUserModel(userIds=user_ids, updateBy=current_user.user.user_name, updateTime=datetime.now())
    delete_user_result = await UserService.delete_user_services(query_db, delete_user)
    logger.info(delete_user_result.message)

    return ResponseUtil.success(msg=delete_user_result.message)


@user_controller.put(
    '/resetPwd',
    summary='重置用户密码接口',
    description='用于重置用户密码',
    response_model=ResponseBaseModel,
    dependencies=[UserInterfaceAuthDependency('system:user:resetPwd')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def reset_system_user_pwd(
    request: Request,
    reset_user: EditUserModel,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
    await UserService.check_user_allowed_services(reset_user)
    if not current_user.user.admin:
        await UserService.check_user_data_scope_services(query_db, reset_user.user_id, data_scope_sql)
    edit_user = EditUserModel(
        userId=reset_user.user_id,
        password=PwdUtil.get_password_hash(reset_user.password),
        pwdUpdateDate=datetime.now(),
        updateBy=current_user.user.user_name,
        updateTime=datetime.now(),
        type='pwd',
    )
    edit_user_result = await UserService.edit_user_services(query_db, edit_user)
    logger.info(edit_user_result.message)

    return ResponseUtil.success(msg=edit_user_result.message)


@user_controller.put(
    '/changeStatus',
    summary='修改用户状态接口',
    description='用于修改用户状态',
    response_model=ResponseBaseModel,
    dependencies=[UserInterfaceAuthDependency('system:user:edit')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def change_system_user_status(
    request: Request,
    change_user: EditUserModel,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
    await UserService.check_user_allowed_services(change_user)
    if not current_user.user.admin:
        await UserService.check_user_data_scope_services(query_db, change_user.user_id, data_scope_sql)
    edit_user = EditUserModel(
        userId=change_user.user_id,
        status=change_user.status,
        updateBy=current_user.user.user_name,
        updateTime=datetime.now(),
        type='status',
    )
    edit_user_result = await UserService.edit_user_services(query_db, edit_user)
    logger.info(edit_user_result.message)

    return ResponseUtil.success(msg=edit_user_result.message)


@user_controller.get(
    '/profile',
    summary='获取用户个人信息接口',
    description='用于获取当前登录用户的个人信息',
    response_model=DynamicResponseModel[UserProfileModel],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_PROFILE)
async def query_detail_system_user_profile(
    request: Request,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
    profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id)
    logger.info(f'获取user_id为{current_user.user.user_id}的信息成功')

    return ResponseUtil.success(model_content=profile_user_result)


@user_controller.get(
    '/{user_id}',
    summary='获取用户详情接口',
    description='用于获取指定用户的详情信息',
    response_model=DynamicResponseModel[UserDetailModel],
    dependencies=[UserInterfaceAuthDependency('system:user:query')],
)
@user_controller.get(
    '/',
    summary='获取用户岗位和角色列表接口',
    description='用于获取当前登录用户可见的岗位和角色列表',
    response_model=DynamicResponseModel[UserDetailModel],
    dependencies=[UserInterfaceAuthDependency('system:user:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_DETAIL)
async def query_detail_system_user(
    request: Request,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
    user_id: int | Literal[''] | None = '',
) -> Response:
    if user_id and not current_user.user.admin:
        await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql)
    detail_user_result = await UserService.user_detail_services(query_db, user_id)
    logger.info(f'获取user_id为{user_id}的信息成功')

    return ResponseUtil.success(model_content=detail_user_result)


@user_controller.post(
    '/profile/avatar',
    summary='修改用户头像接口',
    description='用于修改当前登录用户的头像',
    response_model=DynamicResponseModel[AvatarModel],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_USER_PROFILE_AVATAR, preset=ApiRateLimitPreset.USER_RESOURCE_UPLOAD)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def change_system_user_profile_avatar(
    request: Request,
    avatarfile: Annotated[bytes, File()],
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
    if avatarfile:
        relative_path = (
            f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}'
        )
        dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path)
        try:
            os.makedirs(dir_path)
        except FileExistsError:
            pass
        avatar_name = f'avatar_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.png'
        avatar_path = os.path.join(dir_path, avatar_name)
        async with aiofiles.open(avatar_path, 'wb') as f:
            await f.write(avatarfile)
        edit_user = EditUserModel(
            userId=current_user.user.user_id,
            avatar=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{avatar_name}',
            updateBy=current_user.user.user_name,
            updateTime=datetime.now(),
            type='avatar',
        )
        edit_user_result = await UserService.edit_user_services(query_db, edit_user)
        logger.info(edit_user_result.message)

        return ResponseUtil.success(model_content=AvatarModel(imgUrl=edit_user.avatar), msg=edit_user_result.message)
    return ResponseUtil.failure(msg='上传图片异常，请联系管理员')


@user_controller.put(
    '/profile',
    summary='修改用户个人信息接口',
    description='用于修改当前登录用户的个人信息',
    response_model=ResponseBaseModel,
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def change_system_user_profile_info(
    request: Request,
    user_info: UserInfoModel,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
    edit_user = EditUserModel(
        **user_info.model_dump(exclude_unset=True, by_alias=True, exclude={'role_ids', 'post_ids'}),
        userId=current_user.user.user_id,
        userName=current_user.user.user_name,
        updateBy=current_user.user.user_name,
        updateTime=datetime.now(),
        roleIds=current_user.user.role_ids.split(',') if current_user.user.role_ids else [],
        postIds=current_user.user.post_ids.split(',') if current_user.user.post_ids else [],
        role=current_user.user.role,
    )
    edit_user_result = await UserService.edit_user_services(query_db, edit_user)
    logger.info(edit_user_result.message)

    return ResponseUtil.success(msg=edit_user_result.message)


@user_controller.put(
    '/profile/updatePwd',
    summary='修改用户密码接口',
    description='用于修改当前登录用户的密码',
    response_model=ResponseBaseModel,
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def reset_system_user_password(
    request: Request,
    reset_password: ResetPasswordModel,
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
    reset_user = ResetUserModel(
        userId=current_user.user.user_id,
        oldPassword=reset_password.old_password,
        password=reset_password.new_password,
        pwdUpdateDate=datetime.now(),
        updateBy=current_user.user.user_name,
        updateTime=datetime.now(),
    )
    reset_user_result = await UserService.reset_user_services(query_db, reset_user)
    logger.info(reset_user_result.message)

    return ResponseUtil.success(msg=reset_user_result.message)


@user_controller.post(
    '/importData',
    summary='批量导入用户接口',
    description='用于批量导入用户数据',
    response_model=ResponseBaseModel,
    dependencies=[UserInterfaceAuthDependency('system:user:import')],
)
@ApiRateLimit(
    namespace=ApiNamespace.SYSTEM_USER_IMPORT,
    preset=ApiRateLimitPreset.USER_RESOURCE_IMPORT,
    bypass=ApiRateLimitBypassConfig(roles=('admin',)),
)
@ApiCacheEvict(namespaces=ApiGroup.DATA_SCOPE_MUTATION)
@Log(title='用户管理', business_type=BusinessType.IMPORT)
async def batch_import_system_user(
    request: Request,
    file: Annotated[UploadFile, File(...)],
    update_support: Annotated[bool, Query(alias='updateSupport')],
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    user_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
    dept_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
    batch_import_result = await UserService.batch_import_user_services(
        request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql
    )
    logger.info(batch_import_result.message)

    return ResponseUtil.success(msg=batch_import_result.message)


@user_controller.post(
    '/importTemplate',
    summary='获取用户导入模板接口',
    description='用于获取用户导入模板excel文件',
    response_class=StreamingResponse,
    responses={
        200: {
            'description': '流式返回导入用户模板excel文件',
            'content': {
                'application/octet-stream': {},
            },
        }
    },
    dependencies=[UserInterfaceAuthDependency('system:user:import')],
)
async def export_system_user_template(
    request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
) -> Response:
    user_import_template_result = await UserService.get_user_import_template_services()
    logger.info('获取成功')

    return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result))


@user_controller.post(
    '/export',
    summary='导出用户列表接口',
    description='用于导出当前符合查询条件的用户列表数据',
    response_class=StreamingResponse,
    responses={
        200: {
            'description': '流式返回用户列表excel文件',
            'content': {
                'application/octet-stream': {},
            },
        }
    },
    dependencies=[UserInterfaceAuthDependency('system:user:export')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_USER_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='用户管理', business_type=BusinessType.EXPORT)
async def export_system_user_list(
    request: Request,
    user_page_query: Annotated[UserPageQueryModel, Form()],
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
    # 获取全量数据
    user_query_result = await UserService.get_user_list_services(
        query_db, user_page_query, data_scope_sql, is_page=False
    )
    user_export_result = await UserService.export_user_list_services(user_query_result)
    logger.info('导出成功')

    return ResponseUtil.streaming(data=bytes2file_response(user_export_result))


@user_controller.get(
    '/authRole/{user_id}',
    summary='获取用户已分配角色列表接口',
    description='用于获取指定用户已分配的角色列表',
    response_model=DynamicResponseModel[UserRoleResponseModel],
    dependencies=[UserInterfaceAuthDependency('system:user:query')],
)
async def get_system_allocated_role_list(
    request: Request,
    user_id: Annotated[int, Path(description='用户ID')],
    query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
    user_role_query = UserRoleQueryModel(userId=user_id)
    user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(
        query_db, user_role_query
    )
    logger.info('获取成功')

    return ResponseUtil.success(model_content=user_role_allocated_query_result)


@user_controller.put(
    '/authRole',
    summary='给用户分配角色接口',
    description='用于给指定用户分配角色',
    response_model=ResponseBaseModel,
    dependencies=[UserInterfaceAuthDependency('system:user:edit')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_PERMISSION_MUTATION)
@Log(title='用户管理', business_type=BusinessType.GRANT)
async def update_system_role_user(
    request: Request,
    user_id: Annotated[int, Query(alias='userId')],
    role_ids: Annotated[str, Query(alias='roleIds')],
    query_db: Annotated[AsyncSession, DBSessionDependency()],
    current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
    user_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
    role_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
    if not current_user.user.admin:
        await UserService.check_user_data_scope_services(query_db, user_id, user_data_scope_sql)
        await RoleService.check_role_data_scope_services(query_db, role_ids, role_data_scope_sql)
    add_user_role_result = await UserService.add_user_role_services(
        query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)
    )
    logger.info(add_user_role_result.message)

    return ResponseUtil.success(msg=add_user_role_result.message)
