<?php

declare(strict_types=1);

namespace app\common\service;

use app\admin\model\split\Number;
use app\admin\model\split\Ticket;

/**
 * 工单本地开启号码数（active_number_count）物化字段维护
 *
 * 统计口径：fa_split_number 中 admin_id + split_link_id + ticket_name 匹配且 status=normal
 */
class SplitTicketActiveNumberCountService
{
    /**
     * 按工单关联键统计并回写 active_number_count
     */
    public function refreshForTicketKeys(int $adminId, int $linkId, string $ticketName): void
    {
        $ticketName = trim($ticketName);
        if ($adminId <= 0 || $linkId <= 0 || $ticketName === '') {
            return;
        }

        $count = (int) Number::where('admin_id', $adminId)
            ->where('split_link_id', $linkId)
            ->where('ticket_name', $ticketName)
            ->where('status', 'normal')
            ->count();

        Ticket::where('admin_id', $adminId)
            ->where('split_link_id', $linkId)
            ->where('ticket_name', $ticketName)
            ->update([
                'active_number_count' => $count,
                'updatetime'          => time(),
            ]);
    }

    /**
     * 按工单模型回写
     */
    public function refreshForTicket(Ticket $ticket): void
    {
        $this->refreshForTicketKeys(
            (int) $ticket['admin_id'],
            (int) $ticket['split_link_id'],
            (string) $ticket['ticket_name']
        );
    }

    /**
     * 批量号码 ID：去重后刷新涉及工单
     *
     * @param array<int|string> $ids
     */
    public function refreshForNumberIds(array $ids): void
    {
        $ids = array_values(array_filter(array_map('intval', $ids)));
        if ($ids === []) {
            return;
        }

        $rows = Number::where('id', 'in', $ids)
            ->field('admin_id,split_link_id,ticket_name')
            ->select();

        $this->refreshFromNumberRows($rows);
    }

    /**
     * 编辑单条号码：关联键变更时刷新旧工单与新工单
     *
     * @param array<string, mixed> $before
     * @param array<string, mixed> $after
     */
    public function refreshAfterNumberEdit(array $before, array $after): void
    {
        $keys = [];
        $beforeKey = $this->buildTicketKeyFromRow($before);
        if ($beforeKey !== null) {
            $keys[] = $beforeKey;
        }
        $afterKey = $this->buildTicketKeyFromRow($after);
        if ($afterKey !== null) {
            $keys[] = $afterKey;
        }
        $this->refreshForTicketKeyList($keys);
    }

    /**
     * 批量工单关联键去重后刷新
     *
     * @param array<int, array{0:int,1:int,2:string}> $keys
     */
    public function refreshForTicketKeyList(array $keys): void
    {
        $seen = [];
        foreach ($keys as $key) {
            if (!is_array($key) || count($key) < 3) {
                continue;
            }
            $adminId = (int) $key[0];
            $linkId = (int) $key[1];
            $ticketName = trim((string) $key[2]);
            if ($adminId <= 0 || $linkId <= 0 || $ticketName === '') {
                continue;
            }
            $hash = $adminId . ':' . $linkId . ':' . $ticketName;
            if (isset($seen[$hash])) {
                continue;
            }
            $seen[$hash] = true;
            $this->refreshForTicketKeys($adminId, $linkId, $ticketName);
        }
    }

    /**
     * @param iterable<int, array<string, mixed>|Number> $rows
     */
    public function refreshFromNumberRows(iterable $rows): void
    {
        $keys = [];
        foreach ($rows as $row) {
            $data = $row instanceof Number ? $row->getData() : (array) $row;
            $key = $this->buildTicketKeyFromRow($data);
            if ($key !== null) {
                $keys[] = $key;
            }
        }
        $this->refreshForTicketKeyList($keys);
    }

    /**
     * @param array<string, mixed> $row
     * @return array{0:int,1:int,2:string}|null
     */
    private function buildTicketKeyFromRow(array $row): ?array
    {
        $adminId = (int) ($row['admin_id'] ?? 0);
        $linkId = (int) ($row['split_link_id'] ?? 0);
        $ticketName = trim((string) ($row['ticket_name'] ?? ''));
        if ($adminId <= 0 || $linkId <= 0 || $ticketName === '') {
            return null;
        }

        return [$adminId, $linkId, $ticketName];
    }
}
