<?php

namespace App\Services;

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

class PurchaseService extends Service
{
    /**
     * 매입 목록 조회
     */
    public function index(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->with(['client:id,name', 'approval:id,document_number,title,form_id', 'approval.form:id,name,category']);

        // 검색어 필터
        if (! empty($params['search'])) {
            $search = $params['search'];
            $query->where(function ($q) use ($search) {
                $q->where('purchase_number', 'like', "%{$search}%")
                    ->orWhere('description', 'like', "%{$search}%")
                    ->orWhereHas('client', function ($q) use ($search) {
                        $q->where('name', 'like', "%{$search}%");
                    });
            });
        }

        // 날짜 범위 필터
        if (! empty($params['start_date'])) {
            $query->where('purchase_date', '>=', $params['start_date']);
        }
        if (! empty($params['end_date'])) {
            $query->where('purchase_date', '<=', $params['end_date']);
        }

        // 거래처 필터
        if (! empty($params['client_id'])) {
            $query->where('client_id', $params['client_id']);
        }

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

        // 정렬
        $sortBy = $params['sort_by'] ?? 'purchase_date';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        // 페이지네이션
        $perPage = $params['per_page'] ?? 20;

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

    /**
     * 매입 상세 조회
     */
    public function show(int $id): Purchase
    {
        $tenantId = $this->tenantId();

        return Purchase::query()
            ->where('tenant_id', $tenantId)
            ->with(['client:id,name', 'withdrawal', 'creator:id,name', 'approval:id,document_number,title,form_id,content', 'approval.form:id,name,category'])
            ->findOrFail($id);
    }

    /**
     * 매입 등록
     */
    public function store(array $data): Purchase
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            // 매입번호 자동 생성
            $purchaseNumber = $this->generatePurchaseNumber($tenantId, $data['purchase_date']);

            $purchase = new Purchase;
            $purchase->tenant_id = $tenantId;
            $purchase->purchase_number = $purchaseNumber;
            $purchase->purchase_date = $data['purchase_date'];
            $purchase->client_id = $data['client_id'];
            $purchase->supply_amount = $data['supply_amount'];
            $purchase->tax_amount = $data['tax_amount'];
            $purchase->total_amount = $data['total_amount'];
            $purchase->purchase_type = $data['purchase_type'] ?? null;
            $purchase->description = $data['description'] ?? null;
            $purchase->status = 'draft';
            $purchase->withdrawal_id = $data['withdrawal_id'] ?? null;
            $purchase->approval_id = $data['approval_id'] ?? null;
            $purchase->created_by = $userId;
            $purchase->updated_by = $userId;
            $purchase->save();

            return $purchase->load(['client:id,name']);
        });
    }

    /**
     * 매입 수정
     */
    public function update(int $id, array $data): Purchase
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $purchase = Purchase::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 토글 필드만 업데이트하는 경우는 canEdit 체크 건너뛰기
            $toggleOnlyFields = ['tax_invoice_received'];
            $isToggleOnly = count(array_diff(array_keys($data), $toggleOnlyFields)) === 0;

            // 확정 후에는 수정 불가 (토글 필드만 업데이트하는 경우 제외)
            if (! $isToggleOnly && ! $purchase->canEdit()) {
                throw new \Exception(__('error.purchase.cannot_edit'));
            }

            if (isset($data['purchase_date'])) {
                $purchase->purchase_date = $data['purchase_date'];
            }
            if (isset($data['client_id'])) {
                $purchase->client_id = $data['client_id'];
            }
            if (isset($data['supply_amount'])) {
                $purchase->supply_amount = $data['supply_amount'];
            }
            if (isset($data['tax_amount'])) {
                $purchase->tax_amount = $data['tax_amount'];
            }
            if (isset($data['total_amount'])) {
                $purchase->total_amount = $data['total_amount'];
            }
            if (array_key_exists('description', $data)) {
                $purchase->description = $data['description'];
            }
            if (array_key_exists('withdrawal_id', $data)) {
                $purchase->withdrawal_id = $data['withdrawal_id'];
            }
            if (array_key_exists('purchase_type', $data)) {
                $purchase->purchase_type = $data['purchase_type'];
            }
            if (array_key_exists('tax_invoice_received', $data)) {
                $purchase->tax_invoice_received = $data['tax_invoice_received'];
            }
            if (array_key_exists('approval_id', $data)) {
                $purchase->approval_id = $data['approval_id'];
            }

            $purchase->updated_by = $userId;
            $purchase->save();

            return $purchase->fresh(['client:id,name']);
        });
    }

    /**
     * 매입 삭제
     */
    public function destroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $purchase = Purchase::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            // 확정 후에는 삭제 불가
            if (! $purchase->canDelete()) {
                throw new \Exception(__('error.purchase.cannot_delete'));
            }

            $purchase->deleted_by = $userId;
            $purchase->save();
            $purchase->delete();

            return true;
        });
    }

    /**
     * 매입 확정
     */
    public function confirm(int $id): Purchase
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $purchase = Purchase::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (! $purchase->canConfirm()) {
                throw new \Exception(__('error.purchase.cannot_confirm'));
            }

            $purchase->status = 'confirmed';
            $purchase->updated_by = $userId;
            $purchase->save();

            return $purchase->fresh(['client:id,name']);
        });
    }

    /**
     * 매입 요약 (기간별 합계)
     */
    public function summary(array $params): array
    {
        $tenantId = $this->tenantId();

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

        // 날짜 범위 필터
        if (! empty($params['start_date'])) {
            $query->where('purchase_date', '>=', $params['start_date']);
        }
        if (! empty($params['end_date'])) {
            $query->where('purchase_date', '<=', $params['end_date']);
        }

        // 거래처 필터
        if (! empty($params['client_id'])) {
            $query->where('client_id', $params['client_id']);
        }

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

        // 전체 합계
        $totalSupply = (clone $query)->sum('supply_amount');
        $totalTax = (clone $query)->sum('tax_amount');
        $totalAmount = (clone $query)->sum('total_amount');
        $count = (clone $query)->count();

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

        return [
            'total_supply_amount' => (float) $totalSupply,
            'total_tax_amount' => (float) $totalTax,
            'total_amount' => (float) $totalAmount,
            'total_count' => $count,
            'by_status' => $byStatus,
        ];
    }

    /**
     * 매입유형 일괄 변경
     *
     * @param  array<int>  $ids
     */
    public function bulkUpdatePurchaseType(array $ids, string $purchaseType): int
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereIn('id', $ids)
            ->update([
                'purchase_type' => $purchaseType,
                'updated_by' => $userId,
            ]);
    }

    /**
     * 세금계산서 수취 일괄 설정
     *
     * @param  array<int>  $ids
     */
    public function bulkUpdateTaxReceived(array $ids, bool $taxInvoiceReceived): int
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereIn('id', $ids)
            ->update([
                'tax_invoice_received' => $taxInvoiceReceived,
                'updated_by' => $userId,
            ]);
    }

    /**
     * 대시보드 상세 조회 (CEO 대시보드 모달용)
     *
     * @return array{
     *     summary: array{current_month_total: float, previous_month_total: float, change_rate: float, count: int},
     *     monthly_trend: array<array{label: string, amount: float}>,
     *     by_type: array<array{type: string, type_label: string, amount: float, ratio: float, color: string}>,
     *     items: array<array{id: int, purchase_date: string, vendor_name: string, amount: float, type: string, type_label: string}>
     * }
     */
    public function dashboardDetail(): array
    {
        $tenantId = $this->tenantId();

        // 현재 월 범위
        $currentMonthStart = now()->startOfMonth()->toDateString();
        $currentMonthEnd = now()->endOfMonth()->toDateString();

        // 전월 범위
        $previousMonthStart = now()->subMonth()->startOfMonth()->toDateString();
        $previousMonthEnd = now()->subMonth()->endOfMonth()->toDateString();

        // 1. 요약 정보
        $currentMonthTotal = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('purchase_date', [$currentMonthStart, $currentMonthEnd])
            ->sum('total_amount');

        $previousMonthTotal = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('purchase_date', [$previousMonthStart, $previousMonthEnd])
            ->sum('total_amount');

        $currentMonthCount = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('purchase_date', [$currentMonthStart, $currentMonthEnd])
            ->count();

        $changeRate = $previousMonthTotal > 0
            ? round((($currentMonthTotal - $previousMonthTotal) / $previousMonthTotal) * 100, 1)
            : 0;

        // 2. 월별 추이 (최근 7개월)
        $monthlyTrend = [];
        for ($i = 6; $i >= 0; $i--) {
            $monthStart = now()->subMonths($i)->startOfMonth();
            $monthEnd = now()->subMonths($i)->endOfMonth();

            $amount = Purchase::query()
                ->where('tenant_id', $tenantId)
                ->whereBetween('purchase_date', [$monthStart->toDateString(), $monthEnd->toDateString()])
                ->sum('total_amount');

            $monthlyTrend[] = [
                'label' => $monthStart->format('n').'월',  // "1월", "2월" 형식
                'amount' => (float) $amount,
            ];
        }

        // 3. 유형별 분포 (현재 월)
        $byTypeRaw = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('purchase_date', [$currentMonthStart, $currentMonthEnd])
            ->select('purchase_type', DB::raw('SUM(total_amount) as amount'))
            ->groupBy('purchase_type')
            ->get();

        $byType = [];
        $totalAmount = $byTypeRaw->sum('amount');

        // 유형별 색상 매핑
        $typeColors = [
            'raw_material' => '#60A5FA',    // 원자재 - 파랑
            'sub_material' => '#34D399',    // 부자재 - 초록
            'packaging' => '#FBBF24',       // 포장재 - 노랑
            'consumable' => '#F87171',      // 소모품 - 빨강
            'unset' => '#9CA3AF',           // 미설정 - 회색
        ];
        $colorIndex = 0;
        $defaultColors = ['#60A5FA', '#34D399', '#FBBF24', '#F87171', '#A78BFA', '#F472B6'];

        foreach ($byTypeRaw as $item) {
            $type = $item->purchase_type ?? 'unset';
            $byType[] = [
                'type' => $type,
                'type_label' => Purchase::PURCHASE_TYPES[$type] ?? '미설정',
                'amount' => (float) $item->amount,
                'ratio' => $totalAmount > 0 ? round(($item->amount / $totalAmount) * 100, 1) : 0,
                'color' => $typeColors[$type] ?? $defaultColors[$colorIndex++ % count($defaultColors)],
            ];
        }

        // ratio 내림차순 정렬
        usort($byType, fn ($a, $b) => $b['ratio'] <=> $a['ratio']);

        // 4. 일별 매입 내역 (현재 월)
        $items = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->whereBetween('purchase_date', [$currentMonthStart, $currentMonthEnd])
            ->with(['client:id,name'])
            ->orderBy('purchase_date', 'desc')
            ->get()
            ->map(function ($purchase) {
                $type = $purchase->purchase_type ?? 'unset';

                return [
                    'id' => $purchase->id,
                    'purchase_date' => $purchase->purchase_date->format('Y-m-d'),
                    'vendor_name' => $purchase->client?->name ?? '-',
                    'amount' => (float) $purchase->total_amount,
                    'type' => $type,
                    'type_label' => Purchase::PURCHASE_TYPES[$type] ?? '미설정',
                ];
            })
            ->toArray();

        return [
            'summary' => [
                'current_month_amount' => (float) $currentMonthTotal,
                'previous_month_amount' => (float) $previousMonthTotal,
                'change_rate' => $changeRate,
                'count' => $currentMonthCount,
            ],
            'monthly_trend' => $monthlyTrend,
            'by_type' => $byType,
            'items' => $items,
        ];
    }

    /**
     * 매입번호 자동 생성
     */
    private function generatePurchaseNumber(int $tenantId, string $purchaseDate): string
    {
        $prefix = 'PU'.date('Ymd', strtotime($purchaseDate));

        $lastPurchase = Purchase::query()
            ->where('tenant_id', $tenantId)
            ->where('purchase_number', 'like', $prefix.'%')
            ->orderBy('purchase_number', 'desc')
            ->first();

        if ($lastPurchase) {
            $lastSeq = (int) substr($lastPurchase->purchase_number, -4);
            $newSeq = $lastSeq + 1;
        } else {
            $newSeq = 1;
        }

        return $prefix.str_pad($newSeq, 4, '0', STR_PAD_LEFT);
    }
}
