<?php

namespace Kylin\Payment\Services;

use Kylin\Payment\Models\PaymentRecord;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Illuminate\Contracts\Container\Container;
use Illuminate\Database\Eloquent\Collection;

/**
 * 支付统计分析服务
 */
class PaymentStatisticsService
{
    /**
     * 构造函数
     */
    public function __construct(
        protected readonly Container $app
    ) {
    }

    /**
     * 获取基础统计数据
     */
    public function getBasicStatistics(array $where = []): array
    {
        $query = PaymentRecord::query();

        // 构建查询条件
        foreach ($where as $key => $value) {
            if (is_array($value)) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        // 统计数据
        $totalCount = $query->count();
        $successCount = $query->where('status', PaymentRecord::STATUS_SUCCESS)->count();
        $failedCount = $query->where('status', PaymentRecord::STATUS_FAILED)->count();
        $pendingCount = $query->where('status', PaymentRecord::STATUS_PENDING)->count();
        $refundedCount = $query->where('status', PaymentRecord::STATUS_REFUNDED)->count();
        $closedCount = $query->where('status', PaymentRecord::STATUS_CLOSED)->count();

        // 统计金额
        $totalAmount = $query->sum('amount');
        $successAmount = $query->where('status', PaymentRecord::STATUS_SUCCESS)->sum('amount');
        $refundedAmount = $query->where('status', PaymentRecord::STATUS_REFUNDED)->sum('amount');

        return [
            'total_count' => $totalCount,
            'success_count' => $successCount,
            'failed_count' => $failedCount,
            'pending_count' => $pendingCount,
            'refunded_count' => $refundedCount,
            'closed_count' => $closedCount,
            'total_amount' => $totalAmount,
            'success_amount' => $successAmount,
            'refunded_amount' => $refundedAmount,
            'success_rate' => $totalCount > 0 ? round(($successCount / $totalCount) * 100, 2) : 0,
            'refund_rate' => $successCount > 0 ? round(($refundedCount / $successCount) * 100, 2) : 0,
        ];
    }

    /**
     * 按支付方式统计
     */
    public function getStatisticsByPaymentType(array $where = []): array
    {
        $query = PaymentRecord::query();

        // 构建查询条件
        foreach ($where as $key => $value) {
            if (is_array($value)) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        // 按支付方式分组统计
        $results = $query->select([
            'payment_type',
            DB::raw('COUNT(*) as total_count'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_SUCCESS . '\' THEN 1 ELSE 0 END) as success_count'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_FAILED . '\' THEN 1 ELSE 0 END) as failed_count'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_REFUNDED . '\' THEN 1 ELSE 0 END) as refunded_count'),
            DB::raw('SUM(amount) as total_amount'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_SUCCESS . '\' THEN amount ELSE 0 END) as success_amount'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_REFUNDED . '\' THEN amount ELSE 0 END) as refunded_amount'),
        ])->groupBy('payment_type')->get();

        return $results->toArray();
    }

    /**
     * 按日期统计
     */
    public function getStatisticsByDate(string $period = 'day', array $where = [], int $days = 30): array
    {
        $query = PaymentRecord::query();

        // 构建查询条件
        foreach ($where as $key => $value) {
            if (is_array($value)) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        // 添加日期范围
        $startDate = Carbon::now()->subDays($days);
        $query->where('created_at', '>=', $startDate);

        // 按日期分组统计
        $dateFormat = $this->getDateFormat($period);
        $results = $query->select([
            DB::raw('DATE_FORMAT(created_at, \'' . $dateFormat . '\') as date'),
            DB::raw('COUNT(*) as total_count'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_SUCCESS . '\' THEN 1 ELSE 0 END) as success_count'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_FAILED . '\' THEN 1 ELSE 0 END) as failed_count'),
            DB::raw('SUM(amount) as total_amount'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_SUCCESS . '\' THEN amount ELSE 0 END) as success_amount'),
        ])->groupBy('date')->orderBy('date')->get();

        // 填充缺失的日期
        $filledResults = $this->fillMissingDates($results, $period, $days);

        return $filledResults;
    }

    /**
     * 按状态统计
     */
    public function getStatisticsByStatus(array $where = []): array
    {
        $query = PaymentRecord::query();

        // 构建查询条件
        foreach ($where as $key => $value) {
            if (is_array($value)) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        // 按状态分组统计
        $results = $query->select([
            'status',
            DB::raw('COUNT(*) as count'),
            DB::raw('SUM(amount) as amount'),
        ])->groupBy('status')->get();

        // 状态映射
        $statusMap = [
            PaymentRecord::STATUS_PENDING => '待支付',
            PaymentRecord::STATUS_SUCCESS => '支付成功',
            PaymentRecord::STATUS_FAILED => '支付失败',
            PaymentRecord::STATUS_REFUNDED => '已退款',
            PaymentRecord::STATUS_CLOSED => '已关闭',
        ];

        // 格式化结果
        $formattedResults = [];
        foreach ($results as $result) {
            $formattedResults[] = [
                'status' => $result->status,
                'status_name' => $statusMap[$result->status] ?? $result->status,
                'count' => $result->count,
                'amount' => $result->amount,
            ];
        }

        return $formattedResults;
    }

    /**
     * 获取支付趋势
     */
    public function getPaymentTrend(string $period = 'day', array $where = [], int $days = 30): array
    {
        return $this->getStatisticsByDate($period, $where, $days);
    }

    /**
     * 获取退款统计
     */
    public function getRefundStatistics(array $where = []): array
    {
        $query = PaymentRecord::query();

        // 构建查询条件
        foreach ($where as $key => $value) {
            if (is_array($value)) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        // 只统计已退款的记录
        $query->where('status', PaymentRecord::STATUS_REFUNDED);

        // 统计数据
        $totalCount = $query->count();
        $totalAmount = $query->sum('amount');

        // 按支付方式统计退款
        $refundByPaymentType = $query->select([
            'payment_type',
            DB::raw('COUNT(*) as count'),
            DB::raw('SUM(amount) as amount'),
        ])->groupBy('payment_type')->get();

        return [
            'total_count' => $totalCount,
            'total_amount' => $totalAmount,
            'by_payment_type' => $refundByPaymentType->toArray(),
        ];
    }

    /**
     * 获取支付成功率排名
     */
    public function getSuccessRateRanking(array $where = [], int $limit = 10): array
    {
        $query = PaymentRecord::query();

        // 构建查询条件
        foreach ($where as $key => $value) {
            if (is_array($value)) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        // 按支付方式分组统计成功率
        $results = $query->select([
            'payment_type',
            DB::raw('COUNT(*) as total_count'),
            DB::raw('SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_SUCCESS . '\' THEN 1 ELSE 0 END) as success_count'),
            DB::raw('ROUND((SUM(CASE WHEN status = \'' . PaymentRecord::STATUS_SUCCESS . '\' THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2) as success_rate'),
        ])->groupBy('payment_type')->having('total_count', '>', 0)->orderBy('success_rate', 'desc')->limit($limit)->get();

        return $results->toArray();
    }

    /**
     * 获取日期格式
     */
    protected function getDateFormat(string $period): string
    {
        return match ($period) {
            'hour' => '%Y-%m-%d %H:00',
            'day' => '%Y-%m-%d',
            'week' => '%Y-%u',
            'month' => '%Y-%m',
            default => '%Y-%m-%d',
        };
    }

    /**
     * 填充缺失的日期
     */
    protected function fillMissingDates(Collection $results, string $period, int $days): array
    {
        $startDate = Carbon::now()->subDays($days - 1);
        $endDate = Carbon::now();
        $filledResults = [];

        // 创建结果映射
        $resultMap = [];
        foreach ($results as $result) {
            $resultMap[$result->date] = $result;
        }

        // 填充日期
        $fillDate = function (callable $dateFormatter, callable $dateIncrementer) use (&$filledResults, $resultMap, $startDate, $endDate) {
            $current = $startDate->copy();
            while ($current <= $endDate) {
                $dateKey = $dateFormatter($current);
                if (isset($resultMap[$dateKey])) {
                    $filledResults[] = $resultMap[$dateKey]->toArray();
                } else {
                    $filledResults[] = [
                        'date' => $dateKey,
                        'total_count' => 0,
                        'success_count' => 0,
                        'failed_count' => 0,
                        'total_amount' => 0,
                        'success_amount' => 0,
                    ];
                }
                $dateIncrementer($current);
            }
        };

        match ($period) {
            'hour' => $fillDate(
                fn ($date) => $date->format('Y-m-d H:00'),
                fn (&$date) => $date->addHour()
            ),
            'day' => $fillDate(
                fn ($date) => $date->format('Y-m-d'),
                fn (&$date) => $date->addDay()
            ),
            'month' => $fillDate(
                fn ($date) => $date->format('Y-m'),
                fn (&$date) => $date->addMonth()
            ),
        };

        return $filledResults;
    }
}
