<?php

namespace App\Services;

use App\Models\Tenants\TaxInvoice;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

/**
 * 세금계산서 관리 서비스
 */
class TaxInvoiceService extends Service
{
    public function __construct(
        private BarobillService $barobillService
    ) {}

    // =========================================================================
    // 목록 조회
    // =========================================================================

    /**
     * 세금계산서 목록 조회
     */
    public function list(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();
        $perPage = $params['per_page'] ?? 20;

        $query = TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->orderBy('issue_date', 'desc')
            ->orderBy('id', 'desc');

        // 방향 (매출/매입)
        if (! empty($params['direction'])) {
            $query->where('direction', $params['direction']);
        }

        // 상태
        if (! empty($params['status'])) {
            $query->where('status', $params['status']);
        }

        // 세금계산서 유형
        if (! empty($params['invoice_type'])) {
            $query->where('invoice_type', $params['invoice_type']);
        }

        // 발행 유형
        if (! empty($params['issue_type'])) {
            $query->where('issue_type', $params['issue_type']);
        }

        // 기간 검색
        if (! empty($params['issue_date_from'])) {
            $query->whereDate('issue_date', '>=', $params['issue_date_from']);
        }
        if (! empty($params['issue_date_to'])) {
            $query->whereDate('issue_date', '<=', $params['issue_date_to']);
        }

        // 거래처 검색 (공급자 또는 공급받는자)
        if (! empty($params['corp_num'])) {
            $query->where(function ($q) use ($params) {
                $q->where('supplier_corp_num', $params['corp_num'])
                    ->orWhere('buyer_corp_num', $params['corp_num']);
            });
        }

        // 거래처명 검색
        if (! empty($params['corp_name'])) {
            $query->where(function ($q) use ($params) {
                $q->where('supplier_corp_name', 'like', '%'.$params['corp_name'].'%')
                    ->orWhere('buyer_corp_name', 'like', '%'.$params['corp_name'].'%');
            });
        }

        // 국세청 승인번호 검색
        if (! empty($params['nts_confirm_num'])) {
            $query->where('nts_confirm_num', 'like', '%'.$params['nts_confirm_num'].'%');
        }

        return $query->paginate($perPage);
    }

    /**
     * 세금계산서 상세 조회
     */
    public function show(int $id): TaxInvoice
    {
        $tenantId = $this->tenantId();

        return TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->with(['creator', 'updater'])
            ->findOrFail($id);
    }

    // =========================================================================
    // 세금계산서 생성/수정
    // =========================================================================

    /**
     * 세금계산서 생성
     */
    public function create(array $data): TaxInvoice
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 합계금액 계산
        $data['total_amount'] = ($data['supply_amount'] ?? 0) + ($data['tax_amount'] ?? 0);

        $taxInvoice = TaxInvoice::create(array_merge($data, [
            'tenant_id' => $tenantId,
            'status' => TaxInvoice::STATUS_DRAFT,
            'created_by' => $userId,
            'updated_by' => $userId,
        ]));

        return $taxInvoice->fresh();
    }

    /**
     * 세금계산서 수정
     */
    public function update(int $id, array $data): TaxInvoice
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $taxInvoice = TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        if (! $taxInvoice->canEdit()) {
            throw new \Symfony\Component\HttpKernel\Exception\BadRequestHttpException(__('error.tax_invoice.cannot_edit'));
        }

        // 합계금액 계산
        if (isset($data['supply_amount']) || isset($data['tax_amount'])) {
            $supplyAmount = $data['supply_amount'] ?? $taxInvoice->supply_amount;
            $taxAmount = $data['tax_amount'] ?? $taxInvoice->tax_amount;
            $data['total_amount'] = $supplyAmount + $taxAmount;
        }

        $taxInvoice->fill(array_merge($data, ['updated_by' => $userId]));
        $taxInvoice->save();

        return $taxInvoice->fresh();
    }

    /**
     * 세금계산서 삭제
     */
    public function delete(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $taxInvoice = TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        if (! $taxInvoice->canEdit()) {
            throw new \Symfony\Component\HttpKernel\Exception\BadRequestHttpException(__('error.tax_invoice.cannot_delete'));
        }

        $taxInvoice->deleted_by = $userId;
        $taxInvoice->save();

        return $taxInvoice->delete();
    }

    // =========================================================================
    // 발행/취소
    // =========================================================================

    /**
     * 세금계산서 발행
     */
    public function issue(int $id): TaxInvoice
    {
        $tenantId = $this->tenantId();

        $taxInvoice = TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        if (! $taxInvoice->canEdit()) {
            throw new \Symfony\Component\HttpKernel\Exception\BadRequestHttpException(__('error.tax_invoice.already_issued'));
        }

        return $this->barobillService->issueTaxInvoice($taxInvoice);
    }

    /**
     * 세금계산서 일괄 발행
     *
     * @param  array<int>  $ids  발행할 세금계산서 ID 배열
     * @return array{issued: int, failed: int, errors: array<int, string>}
     */
    public function bulkIssue(array $ids): array
    {
        $tenantId = $this->tenantId();
        $results = [
            'issued' => 0,
            'failed' => 0,
            'errors' => [],
        ];

        $taxInvoices = TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->whereIn('id', $ids)
            ->get();

        foreach ($taxInvoices as $taxInvoice) {
            try {
                if (! $taxInvoice->canEdit()) {
                    $results['errors'][$taxInvoice->id] = __('error.tax_invoice.already_issued');
                    $results['failed']++;

                    continue;
                }

                $this->barobillService->issueTaxInvoice($taxInvoice);
                $results['issued']++;
            } catch (\Throwable $e) {
                $results['errors'][$taxInvoice->id] = $e->getMessage();
                $results['failed']++;
            }
        }

        // 요청된 ID 중 찾지 못한 것들도 실패 처리
        $foundIds = $taxInvoices->pluck('id')->toArray();
        $notFoundIds = array_diff($ids, $foundIds);
        foreach ($notFoundIds as $notFoundId) {
            $results['errors'][$notFoundId] = __('error.tax_invoice.not_found');
            $results['failed']++;
        }

        return $results;
    }

    /**
     * 세금계산서 취소
     */
    public function cancel(int $id, string $reason): TaxInvoice
    {
        $tenantId = $this->tenantId();

        $taxInvoice = TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        return $this->barobillService->cancelTaxInvoice($taxInvoice, $reason);
    }

    /**
     * 국세청 전송 상태 조회
     */
    public function checkStatus(int $id): TaxInvoice
    {
        $tenantId = $this->tenantId();

        $taxInvoice = TaxInvoice::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($id);

        return $this->barobillService->checkNtsSendStatus($taxInvoice);
    }

    // =========================================================================
    // 통계
    // =========================================================================

    /**
     * 세금계산서 요약 통계
     */
    public function summary(array $params): array
    {
        $tenantId = $this->tenantId();

        $query = TaxInvoice::query()
            ->where('tenant_id', $tenantId);

        // 기간 필터
        if (! empty($params['issue_date_from'])) {
            $query->whereDate('issue_date', '>=', $params['issue_date_from']);
        }
        if (! empty($params['issue_date_to'])) {
            $query->whereDate('issue_date', '<=', $params['issue_date_to']);
        }

        // 방향별 통계
        $summary = $query->clone()
            ->select([
                'direction',
                DB::raw('COUNT(*) as count'),
                DB::raw('SUM(supply_amount) as supply_amount'),
                DB::raw('SUM(tax_amount) as tax_amount'),
                DB::raw('SUM(total_amount) as total_amount'),
            ])
            ->groupBy('direction')
            ->get()
            ->keyBy('direction')
            ->toArray();

        // 상태별 통계
        $byStatus = $query->clone()
            ->select([
                'status',
                DB::raw('COUNT(*) as count'),
            ])
            ->groupBy('status')
            ->get()
            ->keyBy('status')
            ->toArray();

        return [
            'by_direction' => [
                'sales' => $summary[TaxInvoice::DIRECTION_SALES] ?? [
                    'count' => 0,
                    'supply_amount' => 0,
                    'tax_amount' => 0,
                    'total_amount' => 0,
                ],
                'purchases' => $summary[TaxInvoice::DIRECTION_PURCHASES] ?? [
                    'count' => 0,
                    'supply_amount' => 0,
                    'tax_amount' => 0,
                    'total_amount' => 0,
                ],
            ],
            'by_status' => [
                TaxInvoice::STATUS_DRAFT => $byStatus[TaxInvoice::STATUS_DRAFT]['count'] ?? 0,
                TaxInvoice::STATUS_ISSUED => $byStatus[TaxInvoice::STATUS_ISSUED]['count'] ?? 0,
                TaxInvoice::STATUS_SENT => $byStatus[TaxInvoice::STATUS_SENT]['count'] ?? 0,
                TaxInvoice::STATUS_CANCELLED => $byStatus[TaxInvoice::STATUS_CANCELLED]['count'] ?? 0,
                TaxInvoice::STATUS_FAILED => $byStatus[TaxInvoice::STATUS_FAILED]['count'] ?? 0,
            ],
        ];
    }
}
