<?php

namespace Kylin\LawCase\Services;

use Kylin\LawCase\Models\Fee;
use Kylin\LawCase\Models\Invoice;
use Kylin\LawCase\Models\TimeEntry;
use Kylin\LawCase\Enums\ChargeMethod;
use Kylin\LawCase\Enums\CaseStatus;
use Illuminate\Support\Facades\DB;

/**
 * 费用服务
 *
 * 处理律师费、发票、工时记录等业务逻辑。
 */
class FeeService
{
    public function createFee(array $data): Fee
    {
        return DB::transaction(function () use ($data) {
            $data['fee_no'] = $this->generateFeeNo();
            $data['approval_status'] = 'pending';

            $fee = Fee::create($data);

            $this->audit('fee_created', $fee, ['fee_no' => $fee->fee_no, 'amount' => $fee->amount]);

            return $fee;
        });
    }

    public function updateFee(Fee $fee, array $data): Fee
    {
        // 已审批的费用不允许修改金额和类型
        if ($fee->approval_status !== 'pending') {
            throw new \InvalidArgumentException('已审批的费用不允许修改');
        }

        $fee->update($data);

        $this->audit('fee_updated', $fee, ['fee_no' => $fee->fee_no]);

        return $fee->fresh();
    }

    public function startTimer(int $caseId, int $lawyerId, ?int $feeId = null): TimeEntry
    {
        // 检查该律师是否有正在进行的计时
        $activeTimer = TimeEntry::where('lawyer_id', $lawyerId)
            ->whereNull('end_time')
            ->first();

        if ($activeTimer) {
            throw new \InvalidArgumentException('您有正在进行的计时任务，请先停止');
        }

        return TimeEntry::create([
            'case_id' => $caseId,
            'fee_id' => $feeId,
            'lawyer_id' => $lawyerId,
            'start_time' => now(),
            'is_billable' => true,
        ]);
    }

    public function stopTimer(TimeEntry $timeEntry): TimeEntry
    {
        $timeEntry->update([
            'end_time' => now(),
            'duration' => $timeEntry->calculateDuration(),
        ]);

        return $timeEntry->fresh();
    }

    public function approveFee(Fee $fee, bool $approved, string $reason = ''): Fee
    {
        $fee->update([
            'approval_status' => $approved ? 'approved' : 'rejected',
            'approved_by' => auth()->id(),
            'approved_at' => now(),
            'approval_remark' => $reason,
        ]);

        $this->audit('fee_approved', $fee, [
            'approved' => $approved,
            'reason' => $reason,
        ]);

        return $fee->fresh();
    }

    /**
     * F-FEE-003 收款管理 - 记录收款并更新费用已付金额
     */
    public function recordPayment(Fee $fee, float $amount, ?string $remark = null): Invoice
    {
        return DB::transaction(function () use ($fee, $amount, $remark) {
            // 创建收款记录
            $invoice = Invoice::create([
                'fee_id' => $fee->id,
                'invoice_no' => 'INV-' . now()->format('Ymd') . '-' . str_pad(Invoice::whereDate('created_at', today())->count() + 1, 4, '0', STR_PAD_LEFT),
                'invoice_status' => 'paid',
                'amount' => $amount,
                'issue_date' => now()->toDateString(),
                'description' => $remark,
            ]);

            // 更新费用已付金额
            $fee->increment('paid_amount', $amount);

            $this->audit('fee_payment_recorded', $fee, [
                'invoice_no' => $invoice->invoice_no,
                'amount' => $amount,
            ]);

            return $invoice;
        });
    }

    /**
     * 获取费用的收款记录
     */
    public function getPaymentHistory(Fee $fee)
    {
        return $fee->invoices()->orderByDesc('created_at')->get();
    }

    /**
     * F-FEE-002 自动生成律师费账单
     * 根据计时记录和收费方式自动计算并生成账单
     */
    public function generateInvoice(Fee $fee): Invoice
    {
        if ($fee->approval_status !== 'approved') {
            throw new \InvalidArgumentException('费用未审批通过，无法生成账单');
        }

        $amount = $fee->amount;

        // 计时收费：根据计时记录计算
        if ($fee->charge_method instanceof ChargeMethod
            ? $fee->charge_method === ChargeMethod::HOURLY
            : $fee->charge_method === 'hourly'
        ) {
            $totalMinutes = $fee->timeEntries()
                ->where('is_billable', true)
                ->sum('duration');
            $hourlyRate = $fee->amount; // amount 作为时薪
            $amount = round(($totalMinutes / 60) * $hourlyRate, 2);
        }

        // 风险代理：仅在案件胜诉时生成
        if ($fee->charge_method instanceof ChargeMethod
            ? $fee->charge_method === ChargeMethod::CONTINGENCY
            : $fee->charge_method === 'contingency'
        ) {
            $case = $fee->case;
            if (!$case || $case->case_status !== CaseStatus::CLOSED->value) {
                throw new \InvalidArgumentException('风险代理费用需在案件结案后生成账单');
            }
        }

        return Invoice::create([
            'fee_id' => $fee->id,
            'invoice_no' => 'INV-' . now()->format('Ymd') . '-' . str_pad(Invoice::whereDate('created_at', today())->count() + 1, 4, '0', STR_PAD_LEFT),
            'invoice_status' => 'issued',
            'amount' => $amount,
            'issue_date' => now()->toDateString(),
            'description' => '自动生成账单',
        ]);
    }

    /**
     * F-FEE-002 账单确认
     */
    public function confirmInvoice(Invoice $invoice): Invoice
    {
        $invoice->update(['invoice_status' => 'confirmed']);

        return $invoice->fresh();
    }

    private function generateFeeNo(): string
    {
        $date = now()->format('Ymd');
        $lastFee = Fee::whereDate('created_at', today())
            ->orderByDesc('id')
            ->first();
        $sequence = $lastFee ? (intval(substr($lastFee->fee_no, -4)) + 1) : 1;

        return sprintf('FEE-%s-%04d', $date, $sequence);
    }

    /**
     * 记录费用审计日志
     *
     * 依据《律师法》和《税收征收管理法》，
     * 费用创建、审批、收款等操作需记录审计日志。
     */
    private function audit(string $event, Fee $fee, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => Fee::class,
                'model_id' => $fee->id,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'law-case-fee',
            ]);
        } catch (\Throwable $e) {
            logger()->warning('费用审计日志写入失败', [
                'error' => $e->getMessage(),
                'fee_id' => $fee->id,
                'event' => $event,
            ]);
        }
    }
}
