<?php

namespace App\Services\Admin\Sms;

use App\Repositories\Admin\Sms\AdminSmsTemplateRepository;
use App\Services\Admin\AdminAuditService;

final class AdminSmsTemplateService
{
    public function __construct(
        private readonly AdminSmsTemplateRepository $repo,
        private readonly AdminAuditService $audit,
    ) {}

    public function list(array $filters, int $perPage = 30)
    {
        return $this->repo->paginate($filters, $perPage);
    }

    public function get(int $id): ?object
    {
        return $this->repo->find($id);
    }

    public function create(int $adminId, array $data): array
    {
        $code = strtolower(trim((string)($data['code'] ?? '')));
        if ($code === '' || !preg_match('/^[a-z0-9\-_]{3,60}$/', $code)) {
            return ['ok'=>false, 'message'=>'code는 영문/숫자/대시/언더바 3~60자로 입력하세요.'];
        }

        // 감사로그용: before/after 구성 (민감정보 없음)
        $after = [
            'code' => $code,
            'title' => trim((string)($data['title'] ?? '')),
            'body' => (string)($data['body'] ?? ''),
            'description' => trim((string)($data['description'] ?? '')) ?: null,
            'is_active' => (int)($data['is_active'] ?? 1),
            'created_by' => $adminId,
        ];

        $id = $this->repo->insert($after);

        // ✅ 성공시에만 감사로그 (id가 0/음수면 기록 안 함)
        if ($id > 0) {
            $req = request();
            $this->audit->log(
                actorAdminId: $adminId,
                action: 'admin.template.create',      // 네 컨벤션에 맞게 수정 가능
                targetType: 'template',               // 실제 리소스명에 맞게
                targetId: (int)$id,
                before: null,
                after: array_merge(['id' => (int)$id], $after),
                ip: (string)($req?->ip() ?? ''),
                ua: (string)($req?->userAgent() ?? ''),
            );
        }

        return ['ok'=>true, 'id'=>$id];
    }


    public function update(int $id, array $data): array
    {
        // ✅ before 스냅샷(가능하면) — repo에 find/get이 없으면 lockForUpdate 같은 걸로 맞춰야 함
        // 여기서는 "repo->find($id)"가 있다고 가정하지 않고, 안전하게 try로 감쌈.
        $before = null;
        try {
            if (method_exists($this->repo, 'find')) {
                $before = $this->repo->find($id);
            } elseif (method_exists($this->repo, 'get')) {
                $before = $this->repo->get($id);
            }
        } catch (\Throwable $ignored) {
            $before = null;
        }

        $payload = [
            'title' => trim((string)($data['title'] ?? '')),
            'body' => (string)($data['body'] ?? ''),
            'description' => trim((string)($data['description'] ?? '')) ?: null,
            'is_active' => (int)($data['is_active'] ?? 1),
        ];

        $affected = $this->repo->update($id, $payload);

        // ✅ 기존 리턴 정책 유지
        $ok = ($affected >= 0);

        // ✅ 성공시에만 감사로그
        if ($ok) {
            $req = request();
            $actorAdminId = (int)(auth('admin')->id() ?? 0);

            // actorAdminId를 못 구하면 로그 생략(기존 프로그램 방해 X)
            if ($actorAdminId > 0) {
                $beforeAudit = $before ? (array)$before : ['id' => $id];
                $afterAudit  = array_merge($beforeAudit, $payload);

                $this->audit->log(
                    actorAdminId: $actorAdminId,
                    action: 'admin.template.update',   // 네 컨벤션에 맞게
                    targetType: 'template',
                    targetId: (int)$id,
                    before: $beforeAudit,
                    after: $afterAudit,
                    ip: (string)($req?->ip() ?? ''),
                    ua: (string)($req?->userAgent() ?? ''),
                );
            }
        }

        return ['ok'=>$ok];
    }


    public function activeForSend(int $limit = 200): array
    {
        return $this->repo->listActive($limit);
    }

}
