<?php

namespace Kylin\Payment\Services;

use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
use Kylin\Payment\Facades\Payment;

/**
 * 支付批量操作服务类
 */
class PaymentBatchOperationService
{
    /**
     * 默认批量操作配置
     */
    const DEFAULT_BATCH_CONFIG = [
        'enabled' => true, // 是否启用批量操作
        'batch_size' => 100, // 批处理大小
        'queue_name' => 'payment_batch', // 队列名称
        'timeout' => 3600, // 操作超时时间（秒）
    ];

    /**
     * 构造函数
     */
    public function __construct(
        protected readonly Container $app,
        protected array $config = []
    ) {
        $this->config = array_merge(self::DEFAULT_BATCH_CONFIG, $config);
    }

    /**
     * 批量创建支付订单
     */
    public function batchCreatePayments(array $payments, array $options = []): int
    {
        // 验证批量操作是否启用
        if (!$this->config['enabled']) {
            throw new \Exception('Batch operation is disabled');
        }

        // 验证批量大小
        if (count($payments) > $this->config['batch_size']) {
            throw new \Exception(sprintf('Batch size exceeds limit. Maximum %d items allowed.', $this->config['batch_size']));
        }

        // 创建批量操作记录
        $batchId = DB::table('payment_batch_operations')->insertGetId([
            'type' => 'create_payments',
            'total_count' => count($payments),
            'status' => 'pending',
            'options' => json_encode($options),
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        // 队列处理批量操作
        Queue::pushOn($this->config['queue_name'], fn () => $this->processBatchCreatePayments($batchId, $payments, $options));

        return $batchId;
    }

    /**
     * 处理批量创建支付订单
     */
    protected function processBatchCreatePayments(int $batchId, array $payments, array $options): void
    {
        DB::beginTransaction();

        try {
            // 更新批量操作状态为处理中
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => 'processing',
                    'updated_at' => now(),
                ]);

            $successCount = 0;
            $failedCount = 0;
            $failedItems = [];

            foreach ($payments as $index => $payment) {
                try {
                    // 创建支付订单
                    $paymentId = Payment::create($payment['gateway'], $payment['params']);

                    // 记录成功项
                    DB::table('payment_batch_operation_items')->insert([
                        'batch_id' => $batchId,
                        'item_type' => 'payment',
                        'item_id' => $paymentId,
                        'status' => 'success',
                        'payload' => json_encode($payment),
                        'result' => json_encode(['payment_id' => $paymentId]),
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    $successCount++;
                } catch (\Exception $e) {
                    // 记录失败项
                    DB::table('payment_batch_operation_items')->insert([
                        'batch_id' => $batchId,
                        'item_type' => 'payment',
                        'status' => 'failed',
                        'payload' => json_encode($payment),
                        'error' => $e->getMessage(),
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    $failedCount++;
                    $failedItems[] = [
                        'index' => $index,
                        'error' => $e->getMessage(),
                    ];
                }
            }

            // 更新批量操作状态
            $status = $failedCount > 0 ? 'partial_success' : 'success';
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => $status,
                    'success_count' => $successCount,
                    'failed_count' => $failedCount,
                    'result' => json_encode(['failed_items' => $failedItems]),
                    'updated_at' => now(),
                    'completed_at' => now(),
                ]);

            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();

            // 更新批量操作状态为失败
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => 'failed',
                    'error' => $e->getMessage(),
                    'updated_at' => now(),
                    'completed_at' => now(),
                ]);
        }
    }

    /**
     * 批量退款
     */
    public function batchRefund(array $refunds, array $options = []): int
    {
        // 验证批量操作是否启用
        if (!$this->config['enabled']) {
            throw new \Exception('Batch operation is disabled');
        }

        // 验证批量大小
        if (count($refunds) > $this->config['batch_size']) {
            throw new \Exception(sprintf('Batch size exceeds limit. Maximum %d items allowed.', $this->config['batch_size']));
        }

        // 创建批量操作记录
        $batchId = DB::table('payment_batch_operations')->insertGetId([
            'type' => 'refund',
            'total_count' => count($refunds),
            'status' => 'pending',
            'options' => json_encode($options),
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        // 队列处理批量操作
        Queue::pushOn($this->config['queue_name'], fn () => $this->processBatchRefund($batchId, $refunds, $options));

        return $batchId;
    }

    /**
     * 处理批量退款
     */
    protected function processBatchRefund(int $batchId, array $refunds, array $options): void
    {
        DB::beginTransaction();

        try {
            // 更新批量操作状态为处理中
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => 'processing',
                    'updated_at' => now(),
                ]);

            $successCount = 0;
            $failedCount = 0;
            $failedItems = [];

            foreach ($refunds as $index => $refund) {
                try {
                    // 执行退款
                    $refundId = Payment::refund($refund['gateway'], $refund['params']);

                    // 记录成功项
                    DB::table('payment_batch_operation_items')->insert([
                        'batch_id' => $batchId,
                        'item_type' => 'refund',
                        'item_id' => $refundId,
                        'status' => 'success',
                        'payload' => json_encode($refund),
                        'result' => json_encode(['refund_id' => $refundId]),
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    $successCount++;
                } catch (\Exception $e) {
                    // 记录失败项
                    DB::table('payment_batch_operation_items')->insert([
                        'batch_id' => $batchId,
                        'item_type' => 'refund',
                        'status' => 'failed',
                        'payload' => json_encode($refund),
                        'error' => $e->getMessage(),
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    $failedCount++;
                    $failedItems[] = [
                        'index' => $index,
                        'error' => $e->getMessage(),
                    ];
                }
            }

            // 更新批量操作状态
            $status = $failedCount > 0 ? 'partial_success' : 'success';
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => $status,
                    'success_count' => $successCount,
                    'failed_count' => $failedCount,
                    'result' => json_encode(['failed_items' => $failedItems]),
                    'updated_at' => now(),
                    'completed_at' => now(),
                ]);

            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();

            // 更新批量操作状态为失败
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => 'failed',
                    'error' => $e->getMessage(),
                    'updated_at' => now(),
                    'completed_at' => now(),
                ]);
        }
    }

    /**
     * 批量查询支付状态
     */
    public function batchQuery(array $queries, array $options = []): int
    {
        // 验证批量操作是否启用
        if (!$this->config['enabled']) {
            throw new \Exception('Batch operation is disabled');
        }

        // 验证批量大小
        if (count($queries) > $this->config['batch_size']) {
            throw new \Exception(sprintf('Batch size exceeds limit. Maximum %d items allowed.', $this->config['batch_size']));
        }

        // 创建批量操作记录
        $batchId = DB::table('payment_batch_operations')->insertGetId([
            'type' => 'query',
            'total_count' => count($queries),
            'status' => 'pending',
            'options' => json_encode($options),
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        // 队列处理批量操作
        Queue::pushOn($this->config['queue_name'], fn () => $this->processBatchQuery($batchId, $queries, $options));

        return $batchId;
    }

    /**
     * 处理批量查询支付状态
     */
    protected function processBatchQuery(int $batchId, array $queries, array $options): void
    {
        DB::beginTransaction();

        try {
            // 更新批量操作状态为处理中
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => 'processing',
                    'updated_at' => now(),
                ]);

            $successCount = 0;
            $failedCount = 0;
            $failedItems = [];

            foreach ($queries as $index => $query) {
                try {
                    // 执行查询
                    $result = Payment::query($query['gateway'], $query['params']);

                    // 记录成功项
                    DB::table('payment_batch_operation_items')->insert([
                        'batch_id' => $batchId,
                        'item_type' => 'query',
                        'status' => 'success',
                        'payload' => json_encode($query),
                        'result' => json_encode($result),
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    $successCount++;
                } catch (\Exception $e) {
                    // 记录失败项
                    DB::table('payment_batch_operation_items')->insert([
                        'batch_id' => $batchId,
                        'item_type' => 'query',
                        'status' => 'failed',
                        'payload' => json_encode($query),
                        'error' => $e->getMessage(),
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    $failedCount++;
                    $failedItems[] = [
                        'index' => $index,
                        'error' => $e->getMessage(),
                    ];
                }
            }

            // 更新批量操作状态
            $status = $failedCount > 0 ? 'partial_success' : 'success';
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => $status,
                    'success_count' => $successCount,
                    'failed_count' => $failedCount,
                    'result' => json_encode(['failed_items' => $failedItems]),
                    'updated_at' => now(),
                    'completed_at' => now(),
                ]);

            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();

            // 更新批量操作状态为失败
            DB::table('payment_batch_operations')
                ->where('id', $batchId)
                ->update([
                    'status' => 'failed',
                    'error' => $e->getMessage(),
                    'updated_at' => now(),
                    'completed_at' => now(),
                ]);
        }
    }

    /**
     * 获取批量操作状态
     */
    public function getBatchStatus(int $batchId): array
    {
        $batch = DB::table('payment_batch_operations')
            ->where('id', $batchId)
            ->first();

        if (!$batch) {
            throw new \Exception('Batch operation not found');
        }

        return [
            'id' => $batch->id,
            'type' => $batch->type,
            'total_count' => $batch->total_count,
            'success_count' => $batch->success_count,
            'failed_count' => $batch->failed_count,
            'status' => $batch->status,
            'error' => $batch->error,
            'result' => $batch->result ? json_decode($batch->result, true) : null,
            'created_at' => $batch->created_at,
            'updated_at' => $batch->updated_at,
            'completed_at' => $batch->completed_at,
        ];
    }

    /**
     * 获取批量操作项
     */
    public function getBatchItems(int $batchId, ?string $status = null): \Illuminate\Database\Eloquent\Collection
    {
        $query = DB::table('payment_batch_operation_items')->where('batch_id', $batchId);

        if ($status) {
            $query->where('status', $status);
        }

        return $query->orderBy('created_at', 'asc')->get();
    }

    /**
     * 获取批量操作配置
     */
    public function getConfig(): array
    {
        return $this->config;
    }

    /**
     * 设置批量操作配置
     */
    public function setConfig(array $config): self
    {
        $this->config = array_merge($this->config, $config);
        return $this;
    }

    /**
     * 启用批量操作
     */
    public function enable(): self
    {
        $this->config['enabled'] = true;
        return $this;
    }

    /**
     * 禁用批量操作
     */
    public function disable(): self
    {
        $this->config['enabled'] = false;
        return $this;
    }
}
