<?php

namespace app\model;

use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use think\model\relation\HasOne;

class AccountRecord extends Base
{
    public const TYPE_CONTENT = 'content';//内容
    public const TYPE_SPU     = 'spu';//商品
    public const TYPE_OTHER   = 'other';//其他

    public const ACTION_COLLECT    = 'collect';//收藏
    public const ACTION_LIKE       = 'like';//点赞
    public const ACTION_SHARE      = 'share';//分享
    public const ACTION_SEARCH     = 'search';//搜索
    public const ACTION_VIEW       = 'view';//查看
    public const ACTION_REGISTER   = 'register';//注册
    public const ACTION_SHARE_VIEW = 'share_view';//分享内容被查看 记录的account_id为分享人ID

    public const COLLECTED = 1;
    public const LIKED     = 1;

    /**
     * 允许的类型
     *
     * @return string[]
     */
    public static function allowTypes(): array
    {
        return [
            self::TYPE_CONTENT, self::TYPE_OTHER, self::TYPE_SPU
        ];
    }

    /**
     * 允许的操作
     *
     * @return string[]
     */
    public static function allowActions(): array
    {
        return [
            self::ACTION_COLLECT, self::ACTION_LIKE, self::ACTION_SHARE,
            self::ACTION_REGISTER, self::ACTION_VIEW, self::ACTION_SHARE_VIEW
        ];
    }

    /**
     * 内容表允许的操作
     *
     * @return string[]
     */
    public static function archivesActions(): array
    {
        return [
            self::ACTION_COLLECT, self::ACTION_LIKE, self::ACTION_SHARE,
            self::ACTION_VIEW
        ];
    }

    /**
     * 不可撤销的操作 即每次都新增记录 如 分享、咨询、注册
     * 注意：可撤销操作需要防止撤销后重新操作导致的无限制增加统计 即刷数据 如收藏、点赞等
     *
     * @return string[]
     */
    public static function notUndoActions(): array
    {
        return [self::ACTION_SHARE, self::ACTION_REGISTER, self::ACTION_VIEW];
    }

    /**
     * 操作对应字段
     *
     * @return string[]
     */
    public static function actionField(): array
    {
        return [
            self::ACTION_REGISTER   => 'customer',
            self::ACTION_COLLECT    => 'collects',
            self::ACTION_LIKE       => 'likes',
            self::ACTION_VIEW       => 'views',
            self::ACTION_SHARE      => 'shares',
            self::ACTION_SHARE_VIEW => 'views',//分享内容被查看 也增加views
        ];
    }

    /**
     * 概览操作对应字段
     *
     * @return string[]
     */
    public static function overviewField(): array
    {
        return [
            self::ACTION_REGISTER   => 'customer',
            self::ACTION_VIEW       => 'views',
            self::ACTION_SHARE      => 'shares',
            self::ACTION_SHARE_VIEW => 'views',//分享内容被查看 也增加views
        ];
    }

    /**
     * 模型关联：内容文档
     */
    public function archive(): HasOne
    {
        return $this->hasOne(Archives::class, 'id', 'relation_id');
    }

    /**
     * 模型关联：商品
     */
    public function spu(): HasOne
    {
        return $this->hasOne(Spu::class, 'id', 'relation_id');
    }

    /**
     * 记录 收藏、点赞、分享、搜索、咨询、查询
     *
     * @param  int  $accountId
     * @param  int  $relationId
     * @param  string  $type
     * @param  string  $action
     * @return bool
     * @throws ModelNotFoundException
     */
    public static function record(int $accountId, string $type = self::TYPE_CONTENT, string $action = self::ACTION_COLLECT, int $relationId = 0): bool
    {
        Db::startTrans();
        try {
            $now           = date('Y-m-d H:i:s');
            $hadRecord     = false;//是否已经记录 防重复点赞和收藏 无限计数 已记录数据不添加相应统计
            $notUndoAction = self::notUndoActions();
            if (in_array($action, $notUndoAction)) {
                $item = null;
            } else {
                $item = self::where('account_id', $accountId)
                    ->where('relation_id', $relationId)
                    ->where('type', $type)
                    ->where('action', $action)
                    ->find();
            }

            if (!$item) {
                self::create([
                    'account_id'  => $accountId,
                    'relation_id' => $relationId,
                    'type'        => $type,
                    'action'      => $action,
                    'created_at'  => $now,
                    'is_record'   => self::BOOL_TRUE,
                    'recorded_at' => $now,
                ]);
            } else {
                if ($item['is_record'] == self::BOOL_TRUE) {
                    $hadRecord = true;
                }

                $item['is_record']   = self::BOOL_TRUE;
                $item['recorded_at'] = $now;
                $item['type']        = $type;
                $item->save();
            }

            // 更新内容表
            if ($type == self::TYPE_CONTENT && in_array($action, self::archivesActions())) {
                if (in_array($action, $notUndoAction) || !$hadRecord) {
                    //不需撤销的 和 新增加的操作才计入统计
                    $archive = Archives::findById($relationId);
                    $field   = self::actionField()[$action] ?? null;
                    if (!$field) {
                        throw new Exception('操作错误');
                    }
                    if ($archive) {
                        $archive->inc($field)->update();
                    }
                }
            }
            // 更新概览数据表
            Overview::renew($accountId, $action);

            Db::commit();
        } catch (ModelNotFoundException | Exception $e) {
            Db::rollback();
            throw $e;
        }

        return true;
    }

    /**
     * 取消收藏|点赞
     *
     * @param  int  $accountId
     * @param  int  $relationId
     * @param  string  $type
     * @param  string  $action
     * @return bool
     */
    public static function unRecord(int $accountId, int $relationId, string $type, string $action): bool
    {
        Db::startTrans();
        try {
            $item = self::where('account_id', $accountId)
                ->where('relation_id', $relationId)
                ->where('type', $type)
                ->where('action', $action)
                ->find();

            if ($item) {
                $hadUnRecord = $item['is_record'] == self::BOOL_FALSE;

                $item->is_record   = self::BOOL_FALSE;
                $item->recorded_at = null;
                $item->save();

                if ($type == self::TYPE_CONTENT && !$hadUnRecord) {
                    $archive       = Archives::findById($relationId);
                    $archiveUpdate = [];
                    if ($archive) {
                        switch ($action) {
                            case AccountRecord::ACTION_COLLECT:
                                $newCollects               = $archive['collects'] - 1;
                                $newCollects               = $newCollects < 0 ? 0 : $newCollects;
                                $archiveUpdate['collects'] = $newCollects;
                                break;
                            case AccountRecord::ACTION_LIKE:
                                $newLikes               = $archive['likes'] - 1;
                                $newLikes               = $newLikes < 0 ? 0 : $newLikes;
                                $archiveUpdate['likes'] = $newLikes;
                                break;
                        }
                    }
                    if ($archive && count($archiveUpdate)) {
                        Archives::updateById($relationId, $archiveUpdate);
                    }
                }
            }

            Db::commit();
        } catch (Exception $e) {
            Db::rollback();
            return false;
        }

        return true;
    }

    /**
     * 获取已完成的操作
     *
     * @param  int  $accountId
     * @param  int  $relationId
     * @param  string  $type
     * @return array
     */
    public static function getDoneAction(int $accountId, int $relationId, string $type = self::TYPE_CONTENT): array
    {
        if ($accountId <= 0) {
            return [];
        }
        return self::where('is_record', self::COMMON_ON)
            ->where('account_id', $accountId)
            ->where('relation_id', $relationId)
            ->where('type', $type)
            ->column('action');
    }

    /**
     * 获取搜索记录
     *
     * @param  int  $accountId
     * @param  int  $page
     * @param  int  $size
     * @return array|null
     * @throws Exception
     */
    public static function findSearch(int $accountId, int $page = 1, int $size = 20): ?array
    {
        if ($accountId <= 0) {
            return [
                'total'   => 0,
                'current' => $page,
                'size'    => $size,
                'list'    => [],
            ];
        }
        $where[] = ['account_id', '=', $accountId];
        $where[] = ['is_record', '=', self::COMMON_ON];
        return self::findList($where, ['id', 'relation_content keyword'], $page, $size, null, ['recorded_at' => 'desc']);
    }

    /**
     * 获取搜索记录
     *
     * @param  int  $accountId
     * @param  string  $keyword
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function saveSearch(int $accountId, string $keyword): bool
    {
        $item = AccountRecord::where('account_id', $accountId)->where('type', self::TYPE_CONTENT)
            ->where('action', self::ACTION_SEARCH)
            ->where('relation_content', trim($keyword))
            ->find();
        $now  = date('Y-m-d H:i:s');
        if (!$item) {
            AccountRecord::create([
                'type'             => self::TYPE_CONTENT,
                'action'           => self::ACTION_SEARCH,
                'relation_content' => trim($keyword),
                'account_id'       => $accountId,
                'is_record'        => self::COMMON_ON,
                'recorded_at'      => $now,
                'created_at'       => $now,
            ]);
        } else {
            $item->save([
                'is_record'   => self::COMMON_ON,
                'recorded_at' => $now
            ]);
        }

        return true;
    }

    /**
     * 清空搜索记录
     *
     * @param  int  $accountId
     * @return bool
     */
    public static function clearSearch(int $accountId): bool
    {
        if ($accountId <= 0) {
            return true;
        }

        $where = ['account_id' => $accountId, 'type' => self::TYPE_CONTENT, 'action' => self::ACTION_SEARCH];
        AccountRecord::update(['is_record' => self::COMMON_OFF], $where);

        return true;
    }

    /**
     * 记录统计
     *
     * @param  string  $type
     * @param  string  $action
     * @param  int  $accountId
     * @return int
     */
    public static function countByAction(string $type, string $action, int $accountId = 0): int
    {
        $whereMap = ['ar.type' => $type, 'ar.action' => $action, 'ar.is_record' => self::BOOL_TRUE];
        if ($accountId > 0) {
            $whereMap['ar.account_id'] = $accountId;
        }
        try {
            return self::alias('ar')->where($whereMap)->when($type == self::TYPE_CONTENT, function ($q) {
                $q->leftJoin('archives arc', 'arc.id=ar.relation_id')->where('arc.id', '>', 0);
            })->count();
        } catch (Exception $e) {
            return 0;
        }
    }

}