<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
namespace app\service\admin\user;

use app\repository\user\UserRepository;
use app\service\admin\BaseAdminService;
use app\service\InputHelper;
use app\service\RequestHelper;
use app\service\StorageService;
use app\service\domain\user\CoreUserBalanceService;
use app\service\domain\user\CoreUserPointsService;
use app\service\domain\user\CoreUserService;
use think\Request;


/**
 * User Service
 * @package app\service\admin\user
 */
class UserService extends BaseAdminService
{

    /**
     * 用户分页列表
     * @param Request $request 请求对象
     * @return array
     */
    public function list(Request $request): array
    {
        $page = $this->userRepository()->paginateForAdmin([
            'keyword' => $request->get('keyword', ''),
            'user_id' => $request->get('user_id'),
            'status' => $request->get('status'),
            'user_type' => $request->get('user_type'),
            'level_id' => $request->get('level_id'),
            'exclude_id' => $request->get('exclude_id'),
        ], RequestHelper::parseLimit($request, 'limit', 10, 100));

        $items = $page['data'] ?? [];
        foreach ($items as &$item) {
            $id = (int)($item['id'] ?? 0);
            if ($id > 0 && (string)($item['invite_code'] ?? '') === '') {
                $item['invite_code'] = $this->core()->ensureInviteCode($id);
            }
            $item = $this->normalizeUserRow($request, $item);
        }
        unset($item);

        $page['data'] = $items;
        return ['code' => 0, 'data' => $page];
    }


    /**
     * 用户详情
     * @param Request $request 请求对象
     * @return array
     */
    public function detail(Request $request): array
    {
        $id = $request->get('user_id');
        if (!is_numeric($id)) {
            return ['code' => 1, 'msg' => ''];
        }

        $user = $this->userRepository()->findWithRelations((int)$id);
        if (!$user) {
            return ['code' => 1, 'msg' => ''];
        }

        if ((string)$user->invite_code === '') {
            $user->invite_code = $this->core()->ensureInviteCode((int)$user->id);
            $user = $this->userRepository()->findWithRelations((int)$id);
            if (!$user) {
                return ['code' => 1, 'msg' => ''];
            }
        }

        $data = $this->normalizeUserRow($request, $user->toArray());
        $data['parent_info'] = $this->userRepository()->findParentInfo((int)$user->id);
        $data['children_count'] = $this->userRepository()->countChildren((int)$user->id);
        $consumeStats = $this->userRepository()->consumeStats((int)$user->id);
        $moneyStats = $this->userRepository()->moneyStats((int)$user->id);
        $pointsStats = $this->userRepository()->pointsStats((int)$user->id);

        $data['consume_stats'] = $consumeStats;
        $data['money_stats'] = [
            'balance' => InputHelper::normalizeDecimalString($data['balance'] ?? '0', 4),
            'total_in' => InputHelper::normalizeDecimalString($moneyStats['total_in'] ?? '0', 4),
            'total_out' => InputHelper::normalizeDecimalString(InputHelper::absDecimalString($moneyStats['total_out'] ?? '0'), 4),
        ];
        $data['points_stats'] = [
            'total_in' => InputHelper::normalizeDecimalString($pointsStats['total_in'] ?? '0', 2),
            'total_out' => InputHelper::normalizeDecimalString(InputHelper::absDecimalString($pointsStats['total_out'] ?? '0'), 2),
        ];

        $channelAccountRepo = $this->app->make(\app\repository\channel\UserChannelAccountRepository::class);
        $channelAccounts = $channelAccountRepo->findAllByUser((int)$user->id);
        $data['channel_accounts'] = array_map(function (array $row) {
            return [
                'channel' => (string)($row['channel'] ?? ''),
                'channel_text' => $this->getChannelText((string)($row['channel'] ?? '')),
                'openid' => (string)($row['openid'] ?? ''),
                'unionid' => (string)($row['unionid'] ?? ''),
                'provider_uid' => (string)($row['provider_uid'] ?? ''),
                'nickname' => (string)($row['nickname'] ?? ''),
                'avatar' => (string)($row['avatar'] ?? ''),
                'create_time' => InputHelper::normalizeTimeValue($row['create_time'] ?? null),
            ];
        }, $channelAccounts);

        return ['code' => 0, 'data' => $data];
    }


    /**
     * 设置用户等级
     * @param Request $request 请求对象
     * @return array
     */
    public function setLevel(Request $request): array
    {
        $id = $request->post('user_id');
        $levelId = $request->post('level_id');
        if (!is_numeric($id) || !is_numeric($levelId)) {
            return ['code' => 1, 'msg' => ''];
        }
        return $this->core()->setLevel((int)$id, (int)$levelId);
    }


    /**
     * 重置用户密码
     * @param Request $request 请求对象
     * @return array
     */
    public function resetPassword(Request $request): array
    {
        $id = $request->post('user_id');
        if (!is_numeric($id)) {
            return ['code' => 1, 'msg' => ''];
        }
        return $this->core()->resetPassword((int)$id, trim((string)$request->post('new_password', '')));
    }


    /**
     * 用户余额调整
     * @param Request $request 请求对象
     * @return array
     */
    public function balanceAdjust(Request $request): array
    {
        $userId = $request->post('user_id');
        $action = trim((string)$request->post('action', ''));
        $amount = trim((string)$request->post('amount', ''));
        $bizType = trim((string)$request->post('biz_type', 'manual'));
        $remark = trim((string)$request->post('remark', ''));
        $adminUid = (int)($request->uid ?? 0);

        if (!is_numeric($userId)) {
            return ['code' => 1, 'msg' => ''];
        }

        return $this->coreBalance()->adjust((int)$userId, $action, $amount, $bizType, $remark, $adminUid);
    }


    /**
     * 用户积分调整
     * @param Request $request 请求对象
     * @return array
     */
    public function pointsAdjust(Request $request): array
    {
        $userId = $request->post('user_id');
        $action = trim((string)$request->post('action', ''));
        $amount = trim((string)$request->post('amount', ''));
        $bizType = trim((string)$request->post('biz_type', 'manual'));
        $remark = trim((string)$request->post('remark', ''));
        $adminUid = (int)($request->uid ?? 0);

        if (!is_numeric($userId)) {
            return ['code' => 1, 'msg' => ''];
        }

        return $this->corePoints()->adjust((int)$userId, $action, (float)$amount, $bizType, $remark, (string)$adminUid);
    }

    /**
     * 获取用户余额核心服务实例
     * @return CoreUserBalanceService
     */
    private function coreBalance(): CoreUserBalanceService
    {
        return $this->app->make(CoreUserBalanceService::class);
    }

    /**
     * 获取用户积分核心服务实例
     * @return CoreUserPointsService
     */
    private function corePoints(): CoreUserPointsService
    {
        return $this->app->make(CoreUserPointsService::class);
    }

    /**
     * 获取用户核心服务实例
     * @return CoreUserService
     */
    private function core(): CoreUserService
    {
        return $this->app->make(CoreUserService::class);
    }

    /**
     * 渠道标识转中文显示名称
     * @param string $channel 渠道标识
     * @return string 中文名称
     */
    private function getChannelText(string $channel): string
    {
        $map = [
            'wechat_mini' => '',
            'wechat_mp' => '',
            'wechat_open' => '',
            'wechat_h5' => '',
            'alipay' => '',
            'qq' => 'QQ',
            'phone' => '',
        ];

        return $map[$channel] ?? $channel;
    }

    /**
     * 获取用户仓储实例
     * @return UserRepository
     */
    private function userRepository(): UserRepository
    {
        return $this->app->make(UserRepository::class);
    }

    /**
     * 归一化用户行数据（格式化时间、头像URL、验证资料等）
     * @param Request $request 请求对象
     * @param array $row 原始用户行数据
     * @return array 归一化后的数据
     */
    private function normalizeUserRow(Request $request, array $row): array
    {
        $verifyProfile = is_array($row['verify_profile'] ?? null) ? $row['verify_profile'] : [];
        $level = is_array($row['level'] ?? null) ? $row['level'] : [];

        $row['create_time'] = InputHelper::normalizeTimeValue($row['create_time'] ?? null);
        $row['update_time'] = InputHelper::normalizeTimeValue($row['update_time'] ?? null);
        $row['avatar'] = StorageService::toFullAssetUrl($request, (string)($row['avatar'] ?? ''));
        $row['level_id'] = (int)($row['level_id'] ?? 0);
        $row['parent_user_id'] = (int)($row['parent_user_id'] ?? 0);
        $row['level_name'] = (string)($level['name'] ?? '');
        $row['verify_status'] = (int)($row['verify_status'] ?? 0);
        $row['verify_profile'] = [
            'user_type' => (int)($verifyProfile['user_type'] ?? 1),
            'realname' => (string)($verifyProfile['realname'] ?? ''),
            'company_name' => (string)($verifyProfile['company_name'] ?? ''),
            'id_card_no' => (string)($verifyProfile['id_card_no'] ?? ''),
            'verify_remark' => (string)($verifyProfile['verify_remark'] ?? ''),
            'province' => (string)($verifyProfile['province'] ?? ''),
            'city' => (string)($verifyProfile['city'] ?? ''),
            'district' => (string)($verifyProfile['district'] ?? ''),
            'id_card_front' => StorageService::toFullAssetUrl($request, (string)($verifyProfile['id_card_front'] ?? '')),
            'id_card_back' => StorageService::toFullAssetUrl($request, (string)($verifyProfile['id_card_back'] ?? '')),
            'business_license' => StorageService::toFullAssetUrl($request, (string)($verifyProfile['business_license'] ?? '')),
        ];
        unset($row['password'], $row['level']);
        $row['extends'] = is_array($row['extends'] ?? null) ? $row['extends'] : (object)[];
        return $row;
    }
}