<?php

declare(strict_types=1);

namespace Kylin\Retail\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 会员数据删除服务
 *
 * 依据《个人信息保护法》第四十七条：
 * 个人有权要求删除其个人信息。处理者应当在合理期限内删除。
 *
 * 依据《电子商务法》第二十四条：
 * 电子商务经营者应当提供用户注销功能，注销后应删除该用户信息。
 *
 * 删除策略：
 *  - 立即删除：身份信息、联系方式、收货地址
 *  - 保留 30 天：交易记录（用于财务对账）
 *  - 保留 90 天：售后记录（用于争议处理）
 *  - 永久删除：180 天后彻底清除保留数据
 *
 * 使用方式：
 *   $result = MemberDataService::deleteMemberData($memberId);
 *   $result = MemberDataService::deleteMemberData($memberId, deferRetention: true);
 */
final class MemberDataService
{
    /**
     * 立即删除的字段（不做保留，立即清除）
     */
    private const IMMEDIATE_DELETE_FIELDS = [
        'name', 'real_name', 'nickname', 'avatar',
        'phone', 'mobile', 'email', 'id_card_number',
        'province', 'city', 'district', 'address', 'detail_address',
        'open_id', 'union_id', 'wechat_openid',
        'birthday', 'gender',
    ];

    /**
     * 立即删除的关联表
     */
    private const IMMEDIATE_DELETE_TABLES = [
        'member_addresses',   // 收货地址
        'member_favorites',   // 收藏
        'member_carts',       // 购物车
        'member_browse_logs', // 浏览记录
    ];

    /**
     * 延迟删除的关联表（保留用于财务对账）
     */
    private const DELAYED_DELETE_TABLES = [
        'orders' => 30,           // 保留 30 天
        'payments' => 30,         // 保留 30 天
        'after_sales' => 90,      // 保留 90 天
    ];

    /**
     * 删除会员数据
     *
     * @param int $memberId 会员 ID
     * @param bool $deferRetention 是否延迟删除保留数据（默认立即删除）
     * @return array 删除结果
     */
    public static function deleteMemberData(int $memberId, bool $deferRetention = false): array
    {
        $results = [
            'member_id' => $memberId,
            'deleted_at' => now()->toDateTimeString(),
            'immediate' => [],
            'delayed' => [],
            'errors' => [],
        ];

        // 1. 清空会员个人敏感信息
        try {
            $nulls = array_fill_keys(self::IMMEDIATE_DELETE_FIELDS, null);
            $nulls['status'] = 'deleted'; // 标记为已注销
            $nulls['deleted_at'] = now();
            $nulls['deleted_reason'] = '用户主动注销';

            DB::table('members')->where('id', $memberId)->update($nulls);
            $results['immediate'][] = 'members (' . count(self::IMMEDIATE_DELETE_FIELDS) . ' 字段)';
        } catch (\Throwable $e) {
            $results['errors'][] = 'members: ' . $e->getMessage();
            Log::error('会员数据删除失败 - members', ['member_id' => $memberId, 'error' => $e->getMessage()]);
        }

        // 2. 删除关联的个人数据
        foreach (self::IMMEDIATE_DELETE_TABLES as $table) {
            try {
                $count = DB::table($table)->where('member_id', $memberId)->delete();
                $results['immediate'][] = "{$table} ({$count} 条)";
            } catch (\Throwable $e) {
                $results['errors'][] = "{$table}: " . $e->getMessage();
            }
        }

        // 3. 处理延迟删除数据
        if ($deferRetention) {
            foreach (self::DELAYED_DELETE_TABLES as $table => $days) {
                try {
                    $scheduledAt = now()->addDays($days);
                    // 标记为待删除，保留数据但脱敏个人信息
                    $count = DB::table($table)
                        ->where('member_id', $memberId)
                        ->update([
                            'member_id' => 0,                          // 解关联
                            'member_name' => '已注销用户',               // 脱敏
                            'member_phone' => '****',                   // 脱敏
                            'scheduled_delete_at' => $scheduledAt,      // 计划删除时间
                        ]);
                    $results['delayed'][] = "{$table} ({$count} 条, {$days} 天后删除)";
                } catch (\Throwable $e) {
                    $results['errors'][] = "{$table}: " . $e->getMessage();
                }
            }
        } else {
            // 直接删除交易关联数据
            foreach (array_keys(self::DELAYED_DELETE_TABLES) as $table) {
                try {
                    $count = DB::table($table)
                        ->where('member_id', $memberId)
                        ->update([
                            'member_id' => 0,
                            'member_name' => '已注销用户',
                            'member_phone' => '****',
                        ]);
                    $results['delayed'][] = "{$table} 已脱敏 ({$count} 条)";
                } catch (\Throwable $e) {
                    $results['errors'][] = "{$table}: " . $e->getMessage();
                }
            }
        }

        // 4. 记录删除日志
        Log::info('会员数据删除完成', [
            'member_id' => $memberId,
            'operator' => auth()->user()?->name ?? '用户本人',
            'immediate' => $results['immediate'],
            'delayed' => $results['delayed'],
            'law' => '《个人信息保护法》第四十七条',
            'timestamp' => now()->toDateTimeString(),
        ]);

        self::audit('member_data_deleted', $memberId, [
            'defer_retention' => $deferRetention,
            'immediate_count' => count($results['immediate']),
            'delayed_count' => count($results['delayed']),
            'errors_count' => count($results['errors']),
        ]);

        return $results;
    }

    /**
     * 清理已标记为延迟删除的过期数据
     *
     * 应由定时任务每天执行。
     *
     * @return int 清理的记录数
     */
    public static function cleanScheduledDeletes(): int
    {
        $total = 0;
        foreach (array_keys(self::DELAYED_DELETE_TABLES) as $table) {
            try {
                $count = DB::table($table)
                    ->where('scheduled_delete_at', '<=', now())
                    ->where('member_id', 0)
                    ->delete();
                $total += $count;
            } catch (\Throwable $e) {
                Log::error('延迟删除清理失败', ['table' => $table, 'error' => $e->getMessage()]);
            }
        }

        return $total;
    }

    /**
     * 合规声明
     */
    public static function complianceNotice(): string
    {
        return '会员数据删除服务遵循《个人信息保护法》第四十七条和《电子商务法》第二十四条。';
    }

    /**
     * 记录会员数据审计日志
     *
     * 依据《个人信息保护法》和《电子商务法》，
     * 会员数据删除、清理等操作需记录审计日志，便于合规审计。
     */
    private static function audit(string $event, int $memberId, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => 'members',
                'model_id' => $memberId,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'retail-member-data',
            ]);
        } catch (\Throwable $e) {
            Log::warning('会员数据审计日志写入失败', [
                'error' => $e->getMessage(),
                'member_id' => $memberId,
                'event' => $event,
            ]);
        }
    }
}