import { BaseService } from "@buildingai/base";
import { BaseController } from "@buildingai/base";
import {
    ACCOUNT_LOG_SOURCE,
    ACCOUNT_LOG_TYPE,
    ACCOUNT_LOG_TYPE_DESCRIPTION,
} from "@buildingai/constants/shared/account-log.constants";
import { SmsScene } from "@buildingai/constants/shared/sms.constant";
import { AppBillingService } from "@buildingai/core/modules";
import { type UserPlayground } from "@buildingai/db";
import { InjectRepository } from "@buildingai/db/@nestjs/typeorm";
import { Agent, MembershipLevels, UserSubscription } from "@buildingai/db/entities";
import { AccountLog } from "@buildingai/db/entities";
import {
    In,
    IsNull,
    Like,
    MoreThan,
    MoreThanOrEqual,
    Not,
    Repository,
} from "@buildingai/db/typeorm";
import { BuildFileUrl } from "@buildingai/decorators/file-url.decorator";
import { Playground } from "@buildingai/decorators/playground.decorator";
import { DictService, UserDictService } from "@buildingai/dict";
import { HttpErrorFactory } from "@buildingai/errors";
import { WebController } from "@common/decorators/controller.decorator";
import { RolePermissionService } from "@common/modules/auth/services/role-permission.service";
import { SmsService } from "@common/modules/sms/services/sms.service";
import { MenuService } from "@modules/menu/services/menu.service";
import { Body, Get, Inject, Param, Patch, Post, Query } from "@nestjs/common";

import { DatasetMemberService } from "../../../ai/datasets/services/datasets-member.service";
import { UserService } from "../../services/user.service";
import { UserCapacityService } from "../../services/user-capacity.service";
import { AccountLogDto } from "./../../dto/account-log-dto";
import { BindPhoneDto, SendBindPhoneCodeDto } from "./../../dto/bind-phone.dto";
import { ALLOWED_USER_FIELDS, UpdateUserFieldDto } from "./../../dto/update-user-field.dto";

/**
 * 前台用户控制器
 *
 * 处理前台用户信息管理相关功能
 */
@WebController("user")
export class UserWebController extends BaseController {
    private readonly accountLogService: BaseService<AccountLog>;

    /**
     * 构造函数
     *
     * @param userService 用户服务
     * @param rolePermissionService 角色权限服务
     * @param datasetMemberService 知识库成员服务
     * @param dictService 字典服务
     */
    constructor(
        private readonly userService: UserService,
        @Inject(RolePermissionService)
        private readonly rolePermissionService: RolePermissionService,
        private readonly datasetMemberService: DatasetMemberService,
        private readonly smsService: SmsService,
        private readonly dictService: DictService,
        private readonly userDictService: UserDictService,
        @Inject(MenuService)
        private readonly menuService: MenuService,
        @InjectRepository(Agent)
        private readonly agentRepository: Repository<Agent>,
        @InjectRepository(AccountLog)
        private readonly accountLogRepository: Repository<AccountLog>,
        @InjectRepository(UserSubscription)
        private readonly userSubscriptionRepository: Repository<UserSubscription>,
        @InjectRepository(MembershipLevels)
        private readonly membershipLevelsRepository: Repository<MembershipLevels>,
        private readonly userCapacityService: UserCapacityService,
        private readonly appBillingService: AppBillingService,
    ) {
        super();
        this.accountLogService = new BaseService(accountLogRepository);
    }

    /**
     * 获取当前用户信息
     *
     * @param user 当前登录用户
     * @returns 用户信息
     */
    @Get("info")
    @BuildFileUrl(["**.avatar"])
    async getUserInfo(@Playground() user: UserPlayground) {
        // 获取用户信息（排除敏感字段）
        const userInfo = await this.userService.findOneById(user.id, {
            relations: ["role"],
        });

        if (!userInfo) {
            throw HttpErrorFactory.notFound("用户不存在");
        }

        // 获取用户的所有权限码
        const permissionCodes = await this.rolePermissionService.getUserPermissions(user.id);

        const menuTree = await this.menuService.getMenuTreeByPermissions(
            userInfo.isRoot ? [] : permissionCodes,
        );

        // 判断用户是否有权限：有权限就是1，没有权限就是0
        const hasPermissions = user.isRoot === 1 || permissionCodes.length > 0 ? 1 : 0;

        // 获取用户当前最高会员等级ID
        const membershipLevel = await this.userService.getUserHighestMembershipLevel(user.id);
        const spendablePower = await this.appBillingService.getSpendablePower(user.id);

        const {
            mpOpenid,
            openid,
            unionid: _unionid,
            password: _password,
            ...userInfoResult
        } = userInfo;

        return {
            ...userInfoResult,
            power: spendablePower,
            permissions: hasPermissions,
            bindWechat: !!mpOpenid,
            bindWechatOa: !!openid,
            membershipLevel,
            permissionsCodes: permissionCodes,
            menus: menuTree,
            hasPassword: !!userInfo.password,
        };
    }

    /**
     * 搜索用户列表
     *
     * @param keyword 搜索关键词（支持搜索用户名、昵称、邮箱、手机号）
     * @param limit 返回数量限制
     * @param datasetId 知识库ID，用于排除已存在的成员
     * @returns 用户列表（只返回有角色的用户，排除已存在于知识库的成员）
     */
    @Get("search")
    @BuildFileUrl(["**.avatar"])
    async searchUsers(
        @Playground() user: UserPlayground,
        @Query("keyword") keyword?: string,
        @Query("limit") limit?: number,
        @Query("datasetId") datasetId?: string,
    ) {
        const searchLimit = Math.min(limit || 20, 50); // 限制最大返回50条

        // 获取已存在于知识库中的成员用户ID列表
        let excludeUserIds: string[] = [];
        if (datasetId) {
            const existingMembers = await this.datasetMemberService.findAll({
                where: { datasetId, isActive: true },
                select: ["userId"],
            });
            excludeUserIds = existingMembers.map((member) => member.userId);
        }

        // 构建基础查询条件
        const baseCondition: any = {
            status: 1,
            role: Not(IsNull()),
        };

        // 构建排除用户ID的条件
        const excludeIds = [user.id, ...excludeUserIds];
        if (excludeIds.length > 0) {
            baseCondition.id = Not(In(excludeIds));
        }

        // 查询用户列表 - 只返回有角色的用户，排除已存在于知识库的成员
        const users = await this.userService.findAll({
            where: keyword
                ? [
                      {
                          username: Like(`%${keyword}%`),
                          ...baseCondition,
                      },
                      {
                          nickname: Like(`%${keyword}%`),
                          ...baseCondition,
                      },
                      {
                          email: Like(`%${keyword}%`),
                          ...baseCondition,
                      },
                      {
                          phone: Like(`%${keyword}%`),
                          ...baseCondition,
                      },
                  ]
                : baseCondition,
            take: searchLimit,
            order: { createdAt: "DESC" },
            excludeFields: ["password", "phone", "phoneAreaCode", "permissions"],
            relations: ["role"],
        });

        return users;
    }

    /**
     * 修改用户信息（单个字段）
     *
     * @param updateUserFieldDto 更新用户字段DTO
     * @param currentUser 当前登录用户
     * @returns 更新后的用户信息
     */
    @Patch("update-field")
    @BuildFileUrl(["**.avatar"])
    async updateUserField(
        @Body() updateUserFieldDto: UpdateUserFieldDto,
        @Playground() currentUser: UserPlayground,
    ) {
        const { field, value } = updateUserFieldDto;
        let newValue = value;

        // 检查用户是否存在
        const user = await this.userService.findOneById(currentUser.id);
        if (!user) {
            throw HttpErrorFactory.notFound("用户不存在");
        }

        // 验证字段是否允许更新
        if (!ALLOWED_USER_FIELDS.includes(field)) {
            throw HttpErrorFactory.badRequest(`不允许更新字段: ${field}`);
        }

        // 特殊字段验证
        if (field === "email" && newValue) {
            // 检查邮箱是否已被其他用户使用
            const existingUser = await this.userService.findOne({
                where: { email: newValue },
            });
            if (existingUser && existingUser.id !== currentUser.id) {
                throw HttpErrorFactory.badRequest("该邮箱已被其他用户使用");
            }
        }

        if (field === "phone" && newValue) {
            // 检查手机号是否已被其他用户使用
            const existingUser = await this.userService.findOne({
                where: { phone: newValue },
            });
            if (existingUser && existingUser.id !== currentUser.id) {
                throw HttpErrorFactory.badRequest("该手机号已被其他用户使用");
            }
        }

        // 构建更新数据
        const updateData: Record<string, any> = {};
        updateData[field] = newValue;

        // 更新用户信息
        const updatedUser = await this.userService.updateUserById(currentUser.id, updateData, {
            excludeFields: ["password"],
        });

        return {
            user: updatedUser,
            message: `更新成功`,
        };
    }

    /**
     * 发送绑定手机号验证码
     */
    @Post("phone/send-code")
    async sendBindPhoneCode(
        @Body() dto: SendBindPhoneCodeDto,
        @Playground() currentUser: UserPlayground,
    ) {
        const areaCode = dto.areaCode || "86";
        const existingUser = await this.userService.findOne({
            where: { phone: dto.mobile, phoneAreaCode: areaCode },
        });
        if (existingUser && existingUser.id !== currentUser.id) {
            throw HttpErrorFactory.badRequest("该手机号已被其他用户绑定");
        }

        await this.smsService.sendCode(dto.mobile, areaCode, SmsScene.BIND_MOBILE);
        return "The verification code has been sent and is valid for 5 minutes";
    }

    /**
     * 短信验证码绑定手机号
     */
    @Post("phone/bind")
    @BuildFileUrl(["**.avatar"])
    async bindPhone(@Body() dto: BindPhoneDto, @Playground() currentUser: UserPlayground) {
        const areaCode = dto.areaCode || "86";
        const existingUser = await this.userService.findOne({
            where: { phone: dto.mobile, phoneAreaCode: areaCode },
        });
        if (existingUser && existingUser.id !== currentUser.id) {
            throw HttpErrorFactory.badRequest("该手机号已被其他用户绑定");
        }

        await this.smsService.verifyCode(dto.mobile, areaCode, dto.code, SmsScene.BIND_MOBILE);
        const updatedUser = await this.userService.updateUserById(
            currentUser.id,
            {
                phone: dto.mobile,
                phoneAreaCode: areaCode,
            },
            {
                excludeFields: ["password"],
            },
        );

        return {
            user: updatedUser,
            message: "手机号绑定成功",
        };
    }

    /**
     * 账户记录
     * @param accountLogDto
     * @param user
     * @returns
     */
    @Get("account-log")
    async accountLog(@Query() accountLogDto: AccountLogDto, @Playground() user: UserPlayground) {
        const { action } = accountLogDto;

        // 构建查询条件
        const where: any = { userId: user.id };
        if (action !== undefined && action !== "") {
            where.action = action;
        }

        // 获取用户信息
        const spendablePower = await this.appBillingService.getSpendablePower(user.id);

        // 获取订阅积分（所有未过期记录的 availableAmount 总和）
        const now = new Date();
        const membershipGiftLogs = await this.accountLogService.findAll({
            where: {
                userId: user.id,
                accountType: ACCOUNT_LOG_TYPE.MEMBERSHIP_GIFT_INC,
                expireAt: MoreThanOrEqual(now),
                availableAmount: MoreThan(0),
            } as any,
        });
        const membershipGiftPower = membershipGiftLogs.reduce(
            (sum, log) => sum + ((log as any).availableAmount || 0),
            0,
        );

        // 使用 paginate 方法进行分页查询
        const lists = await this.accountLogService.paginate(accountLogDto, {
            where,
            order: {
                createdAt: "DESC",
                accountType: "DESC",
            },
        });

        // 处理返回结果
        const agentIds = new Set<string>();

        // 先收集所有需要查询的智能体ID
        lists.items.forEach((accountLog) => {
            if (
                accountLog.sourceInfo?.type === ACCOUNT_LOG_SOURCE.AGENT_CHAT &&
                accountLog.sourceInfo?.source
            ) {
                agentIds.add(accountLog.sourceInfo.source);
            }
        });

        // 如果有智能体ID，先批量查询
        const agentMap = new Map<string, string>();
        if (agentIds.size > 0) {
            const agentIdArray = Array.from(agentIds);
            try {
                // 批量查询智能体信息
                const agents = await this.agentRepository.find({
                    where: { id: In(agentIdArray) },
                    select: ["id", "name"],
                });

                // 构建ID到名称的映射
                agents.forEach((agent) => {
                    agentMap.set(agent.id, agent.name);
                });
            } catch (error) {
                this.logger.error(`查询智能体信息失败: ${error.message}`);
            }
        }

        // 处理每条记录
        lists.items = lists.items.map((accountLog) => {
            const accountTypeDesc = ACCOUNT_LOG_TYPE_DESCRIPTION[accountLog.accountType];
            let consumeSourceDesc = "";

            // 根据来源类型处理
            if (accountLog.sourceInfo) {
                switch (accountLog.sourceInfo.type) {
                    case ACCOUNT_LOG_SOURCE.AGENT_CHAT:
                        // 如果是智能体对话，使用智能体名称
                        if (agentMap.has(accountLog.sourceInfo.source)) {
                            consumeSourceDesc = agentMap.get(accountLog.sourceInfo.source);
                        } else {
                            consumeSourceDesc = `智能体(${accountLog.sourceInfo.source})`;
                        }
                        break;

                    default:
                        consumeSourceDesc = accountLog.sourceInfo.source;
                }
            }

            return { ...accountLog, accountTypeDesc, consumeSourceDesc };
        });

        return {
            ...lists,
            extend: {
                power: spendablePower,
                //订阅积分
                membershipGiftPower,
                rechargePower: spendablePower - membershipGiftPower,
            },
        };
    }

    /**
     * Get all public user configurations (excludes private groups)
     * Used for frontend localStorage cache
     *
     * @param user Current user
     * @returns All public configurations grouped by group name
     */
    @Get("config")
    async getAllPublicConfigs(@Playground() user: UserPlayground) {
        return this.userDictService.getAllPublicConfigs(user.id);
    }

    /**
     * Get user configurations by specific group
     * Can access any group including private ones
     *
     * @param user Current user
     * @param group Group name
     * @returns User configurations as key-value pairs
     */
    @Get("config/:group")
    async getConfigByGroup(@Playground() user: UserPlayground, @Param("group") group: string) {
        return this.userDictService.getGroupValues(user.id, group);
    }

    /**
     * Set user configuration (single or batch)
     *
     * @param user Current user
     * @param body Configuration data
     * @returns Success status
     */
    @Post("config")
    async setUserConfig(
        @Playground() user: UserPlayground,
        @Body()
        body:
            | { key: string; value: any; group?: string }
            | { items: Array<{ key: string; value: any; group?: string }> },
    ) {
        if ("items" in body && Array.isArray(body.items)) {
            await this.userDictService.mset(user.id, body.items);
        } else if ("key" in body) {
            await this.userDictService.set(user.id, body.key, body.value, { group: body.group });
        }
        return { success: true };
    }

    /**
     * 获取用户存储容量信息
     *
     * @param user 当前登录用户
     * @returns 用户存储容量信息
     */
    @Get("storage")
    async getUserStorage(@Playground() user: UserPlayground) {
        return this.userCapacityService.getUserCapacityInfo(user.id);
    }
}
