<?php

namespace Modules\Manage\Http\Controllers;

use Catch\Exceptions\FailedException;
use Illuminate\Routing\Controller;
use Catch\Base\CatchController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\Channel\Exceptions\ChannelBusinessException;
use Modules\Channel\Models\UserHasMiniprograms;
use Modules\Channel\Services\User\UserService;
use Modules\Common\Errors\Errors;
use Modules\Manage\Enmus\MiniprogramType;
use Modules\Manage\Http\Requests\MiniprogramRequest;
use Modules\Manage\Http\Requests\MiniprogramUpdateRequest;
use Modules\Manage\Models\Miniprogram;
use Modules\User\Http\Controllers\UserTrait;


class MiniprogramController extends CatchController
{

    use UserTrait;

    public function __construct(protected readonly Miniprogram $miniprogram, protected readonly UserHasMiniprograms $userHasMiniprograms)
    {

    }

    const  COMPANY_ROLE = 'company';
    const  ADMINISTRATOR_ROLE = 'administrator';
    const  OPTIMIZER_ROLE = 'optimizer';

    /**
     * 小程序列表
     * @param Request $request
     * @return void
     */
    public function index(Request $request)
    {
        $uid = $this->getLoginUser()->id;
        $name = $request->get('name');
        $play_name = $request->get('play_name');
        $company = $request->get('company');
        $type = $request->get('type');
        $page_size = $request->input('limit', 15);
        $where = [];
        if ($name) {
            $where[] = ['name', 'like', '%' . $name . '%'];
        }
        if ($play_name) {
            $where[] = ['play_name', 'like', '%' . $play_name . '%'];
        }
        if ($company) {
            $where[] = ['company', 'like', '%' . $company . '%'];
        }

        if ($type) {
            $where[] = ['type', '=', $type];
        }
        if (UserService::userHasRole($uid, 'administrator')) {
            $result = $this->miniprogram->where($where)->orderBy('id', 'desc')->paginate($page_size);
        } else {
            $result = $this->userHasMiniprograms->join('miniprogram', 'miniprogram.id', '=', 'user_has_miniprograms.miniprogram_id')
                ->where('user_has_miniprograms.is_enabled', 1)
                ->where('uid', $uid)
                ->where($where)
                ->select('miniprogram.*')
                ->paginate($page_size);
        }

        foreach ($result as $item) {
            $item->type_name = MiniprogramType::from($item->type)->name();
            $item->status_name = $item->status == 1 ? '启用' : '禁用';
            $item->pay_merchant_name = getProp($item->pay_merchant_info, 'name', '-');
            unset($item->pay_merchant_info);
        }
        return $result;
    }

    /**
     * 添加小程序
     *
     * @param MiniprogramRequest $request
     * @return void
     */
    public function store(MiniprogramRequest $request)
    {
        $validate_result = $request->validated();
        $validate_result['remark'] = $request->post('remark', '') ?? '';
        $validate_result['pay_merchant_id'] = $request->post('pay_merchant_id', 0);
        if (getProp($validate_result, 'pay_merchant_id', 0)) {
            $info = DB::table('pay_merchants')->where('id', $validate_result['pay_merchant_id'])->first();
            if (empty($info)) {
                throw  new  FailedException("支付方式不存在");
            }
            if ($info->miniprogram_type != $validate_result['type']) {
                throw  new  FailedException("小程序类型和支付的小程序类型不匹配");
            }
            $validate_result['pay_merchant_info'] = [
                'pay_merchant_id' => $info->id,
                'name' => $info->name,
                'pay_type' => $info->pay_type,
                'payee_name' => $info->payee_name,
                'miniprogram_type' => $info->miniprogram_type,
                'pay_appid' => $info->pay_appid,
            ];

        } else {
            $validate_result['pay_merchant_id'] = 0;
            $validate_result['pay_merchant_info'] = [];
        }

        return $this->miniprogram->create($validate_result)->toArray();

    }

    /**
     * 小程序详情
     *
     * @param [type] $id
     * @return void
     */
    public function show($id)
    {
        return $this->miniprogram->find($id)->toArray();
    }

    /**
     * 更新小程序
     *
     * @param [type] $id
     * @param MiniprogramUpdateRequest $request
     * @return void
     */
    public function update($id, MiniprogramUpdateRequest $request)
    {
        $validate_result = $request->validated();
        if ($request->post('remark', '')) {
            $validate_result['remark'] = $request->post('remark', '');
        }
        if (getProp($validate_result, 'pay_merchant_id', 0)) {
            $info = DB::table('pay_merchants')->where('id', $validate_result['pay_merchant_id'])->first();
            if (empty($info)) {
                throw  new  FailedException("支付方式不存在");
            }
            if ($info->miniprogram_type != $validate_result['type']) {
                throw  new  FailedException("小程序类型和支付的小程序类型不匹配");
            }
            $validate_result['pay_merchant_info'] = [
                'pay_merchant_id' => $info->id,
                'name' => $info->name,
                'pay_type' => $info->pay_type,
                'payee_name' => $info->payee_name,
                'miniprogram_type' => $info->miniprogram_type,
                'pay_appid' => $info->pay_appid,
            ];

        } else {
            $validate_result['pay_merchant_id'] = 0;
            $validate_result['pay_merchant_info'] = [];
        }
        $this->miniprogram->where('id', $id)->update($validate_result);
        return [];
    }


    /**
     * 小程序类型列表
     *
     * @return array [ ['name'=>'微信小程序','id'=>1],[],[] ]
     */
    public function typeList()
    {
        $type_list = MiniprogramType::cases();
        $data = array_map(fn($item) => ['name' => $item->name(), 'value' => $item->value()], $type_list);
        return $data;
    }


    /**
     * 获取所有公司
     *
     * @return void
     */
    public function companyList()
    {
        return $this->miniprogram->select(DB::raw('distinct company'))->get()->pluck('company');
    }


    /**
     * 绑定小程序和投放公司的关系 或者投放公司把小程序分配给优化师
     * @param [type] $miniprogram_id
     * @param Request $request uid=2,3,4,5 actison=on|off on:分配,off取消分配
     * @return array
     *
     */
    public function allocationStore($miniprogram_id, Request $request)
    {
        $uid = $this->getLoginUser()->id;
        if (!UserService::userHasRoles($uid, [self::COMPANY_ROLE, self::ADMINISTRATOR_ROLE])) {
            ChannelBusinessException::throwError(Errors::PARAM_EMPTY);
        }
        $uids = $request->post('uids');
        $action = $request->post('action');
        if (empty($miniprogram_id) || empty($uids) || empty($action) || !in_array($action, ['on', 'off'])) {
            ChannelBusinessException::throwError(Errors::PARAM_EMPTY);
        }

        $miniprogram_info = $this->miniprogram->find($miniprogram_id);
        if (!$miniprogram_info || $miniprogram_info->status == 0) {
            ChannelBusinessException::throwError(Errors::MINIPROGRAM_STATUS_ERROR);
        }
        $userContext = $this->getUserContext(null);
        if ($userContext['loginUserRoles']->contains(self::COMPANY_ROLE)) {
            // 公司给投手分配小程序
            return $this->allocationStoreCompany($miniprogram_id, $uids, $action);
        } else {
            $companyId = explode(',', $uids)[0] ?: 0;
            if (empty($companyId)) {
                ChannelBusinessException::throwError(Errors::PARAM_EMPTY);
            }
            if (!UserService::userHasRoles($companyId, [self::COMPANY_ROLE])) {
                ChannelBusinessException::throwError(Errors::MINIPROGRAM_OWNER_ACCOUNT_ROLE_ERROR);
            }

            // 小程序原拥有公司账号id
            $ownerCompanyId = DB::table('user_has_miniprograms as up')
                ->leftJoin('user_has_roles as ur', 'ur.user_id', '=', 'up.uid')
                ->leftJoin('roles as r', 'r.id', '=', 'ur.role_id')
                ->where('up.is_enabled', 1)
                ->where('up.miniprogram_id', $miniprogram_id)
                ->where('r.identify', 'company')->orderBy('up.id', 'desc')
                ->value('up.uid');
            if ($companyId == $ownerCompanyId) {
                // 相同则不修改
                return true;
            }
            if ($ownerCompanyId > 0) {
                //  若小程序已经分配给其他公司
                $this->userHasMiniprograms::where('miniprogram_id', $miniprogram_id)->update(['is_enabled' => 0]);
            }
            $result = $this->userHasMiniprograms->where('uid', $companyId)->where('miniprogram_id', $miniprogram_id)->first();
            if ($result) {
                if ($result->is_enabled == 0) {
                    $result->is_enabled = 1;
                    $result->save();
                }
                return true;
            }
            $this->userHasMiniprograms->create([
                'uid' => $companyId, 'miniprogram_id' => $miniprogram_id, 'is_enabled' => 1
            ]);
            return true;
        }

    }

    protected function allocationStoreCompany($miniprogram_id, $uids, $action)
    {
        return collect(explode(',', $uids))->filter(function (int $value, int $key) use ($miniprogram_id, $action) {
            $user_access = UserService::userHasRoles($value, [self::COMPANY_ROLE, self::OPTIMIZER_ROLE]);
            //只能分配给投手公司或者优化师
            if ($user_access) {
                $result = $this->userHasMiniprograms->where('uid', $value)->where('miniprogram_id', $miniprogram_id)->first();
                if ($action == 'off') {
                    if ($result) {
                        $result->is_enabled = 0;
                        $result->save();
                    }
                    return true;
                }
                if ($result) {
                    if ($result->is_enabled == 0) {
                        $result->is_enabled = 1;
                        $result->save();
                    }
                    return true;
                }
                $this->userHasMiniprograms->create([
                    'uid' => $value, 'miniprogram_id' => $miniprogram_id, 'is_enabled' => 1
                ]);
                return true;
            }
            return false;
        });
    }

    /**
     * 获取投手公司和小程序的绑定关系,用于前端数据回显
     * @param [type] $miniprogram_id
     * @return []
     * response = [
     *      'on'=>[ ['id'=>1,'username'=>'公司1','user_has_miniprogram'=>1],[]  ],
     *      'off'=>[['id'=>1,'username'=>'公司1','user_has_miniprogram'=>0],[]],
     *      'all'=>[
     *          ['id'=>1,'username'=>'公司1','user_has_miniprogram'=>1],
     *          ['id'=>2,'username'=>'公司1','user_has_miniprogram'=>0]
     *          ]
     *      ]
     *
     */
    public function getAllocationInfo($miniprogram_id)
    {
        $uid = $this->getLoginUser()->id;
        if (UserService::userHasRole($uid, self::ADMINISTRATOR_ROLE)) {
            $all_company_account = UserService::listByRole(self::COMPANY_ROLE, ['users.username', 'users.id']);
        } else {
            $all_company_account = UserService::getOptimizers($uid, ['users.username', 'users.id']);
        }

        $result = $all_company_account->map(function ($item, $key) use ($miniprogram_id) {
            $info = $this->userHasMiniprograms->where('uid', $item->id)->where('miniprogram_id', $miniprogram_id)->where('is_enabled', 1)->count();
            if ($info) {
                $item->user_has_miniprogram = 1;
                $item->user_has_miniprogram_flag = 'on';
            } else {
                $item->user_has_miniprogram = 0;
                $item->user_has_miniprogram_flag = 'off';
            }
            return $item;
        });
        $group = $result->groupBy('user_has_miniprogram_flag')->toArray();
        if (!isset($group['on'])) {
            $group['on'] = [];
        }
        if (!isset($group['off'])) {
            $group['off'] = [];
        }
        $group['all'] = $result->toArray();
        return $group;
    }
}