<?php

namespace App\Services;

use App\Models\Items\ItemReceipt;
use App\Models\Products\Price;
use App\Models\Products\PriceRevision;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

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

        $size = (int) ($params['size'] ?? 20);
        $q = trim((string) ($params['q'] ?? ''));
        $itemType = $params['item_type_code'] ?? null;
        $itemId = $params['item_id'] ?? null;
        $clientGroupId = $params['client_group_id'] ?? null;
        $status = $params['status'] ?? null;
        $validAt = $params['valid_at'] ?? null;

        $query = Price::query()
            ->with(['clientGroup:id,name'])
            ->where('tenant_id', $tenantId);

        // 검색어 필터
        if ($q !== '') {
            $query->where(function ($w) use ($q) {
                $w->where('supplier', 'like', "%{$q}%")
                    ->orWhere('note', 'like', "%{$q}%");
            });
        }

        // 품목 유형 필터
        if ($itemType) {
            $query->where('item_type_code', $itemType);
        }

        // 품목 ID 필터
        if ($itemId) {
            $query->where('item_id', (int) $itemId);
        }

        // 고객그룹 필터
        if ($clientGroupId !== null) {
            if ($clientGroupId === 'null' || $clientGroupId === '') {
                $query->whereNull('client_group_id');
            } else {
                $query->where('client_group_id', (int) $clientGroupId);
            }
        }

        // 상태 필터
        if ($status) {
            $query->where('status', $status);
        }

        // 특정 일자에 유효한 단가 필터
        if ($validAt) {
            $query->validAt($validAt);
        }

        return $query->orderByDesc('id')->paginate($size);
    }

    /**
     * 단가 상세 조회
     */
    public function show(int $id): Price
    {
        $tenantId = $this->tenantId();

        $price = Price::query()
            ->with(['clientGroup:id,name', 'revisions' => function ($q) {
                $q->orderByDesc('revision_number')->limit(10);
            }])
            ->where('tenant_id', $tenantId)
            ->find($id);

        if (! $price) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        return $price;
    }

    /**
     * 단가 등록
     */
    public function store(array $data): Price
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            // 중복 체크 (동일 품목+고객그룹+시작일)
            $this->checkDuplicate(
                $tenantId,
                $data['item_type_code'],
                (int) $data['item_id'],
                $data['client_group_id'] ?? null,
                $data['effective_from']
            );

            // 기존 무기한 단가의 종료일 자동 설정
            $this->autoCloseExistingPrice(
                $tenantId,
                $data['item_type_code'],
                (int) $data['item_id'],
                $data['client_group_id'] ?? null,
                $data['effective_from']
            );

            $payload = array_merge($data, [
                'tenant_id' => $tenantId,
                'status' => $data['status'] ?? 'draft',
                'is_final' => false,
                'created_by' => $userId,
            ]);

            // 판매단가 자동 계산 (sales_price가 없고 필요 데이터가 있을 때)
            if (empty($payload['sales_price']) && isset($payload['purchase_price'])) {
                $tempPrice = new Price($payload);
                $payload['sales_price'] = $tempPrice->calculateSalesPrice();
            }

            $price = Price::create($payload);

            // 최초 리비전 생성
            $this->createRevision($price, null, $userId, __('message.pricing.created'));

            return $price;
        });
    }

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

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $price = Price::query()
                ->where('tenant_id', $tenantId)
                ->find($id);

            if (! $price) {
                throw new NotFoundHttpException(__('error.not_found'));
            }

            // 확정된 단가는 수정 불가
            if (! $price->canEdit()) {
                throw new BadRequestHttpException(__('error.pricing.finalized_cannot_edit'));
            }

            // 변경 전 스냅샷
            $beforeSnapshot = $price->toSnapshot();

            // 키 변경 시 중복 체크
            $itemType = $data['item_type_code'] ?? $price->item_type_code;
            $itemId = $data['item_id'] ?? $price->item_id;
            $clientGroupId = $data['client_group_id'] ?? $price->client_group_id;
            $effectiveFrom = $data['effective_from'] ?? $price->effective_from;

            $keyChanged = (
                $itemType !== $price->item_type_code ||
                $itemId !== $price->item_id ||
                $clientGroupId !== $price->client_group_id ||
                $effectiveFrom != $price->effective_from
            );

            if ($keyChanged) {
                $this->checkDuplicate($tenantId, $itemType, $itemId, $clientGroupId, $effectiveFrom, $id);
            }

            $data['updated_by'] = $userId;
            $price->update($data);

            // 판매단가 재계산 (관련 필드가 변경된 경우)
            if ($this->shouldRecalculateSalesPrice($data)) {
                $price->sales_price = $price->calculateSalesPrice();
                $price->save();
            }

            $price->refresh();

            // 리비전 생성
            $changeReason = $data['change_reason'] ?? null;
            $this->createRevision($price, $beforeSnapshot, $userId, $changeReason);

            return $price;
        });
    }

    /**
     * 단가 삭제 (soft delete)
     */
    public function destroy(int $id): void
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        DB::transaction(function () use ($id, $tenantId, $userId) {
            $price = Price::query()
                ->where('tenant_id', $tenantId)
                ->find($id);

            if (! $price) {
                throw new NotFoundHttpException(__('error.not_found'));
            }

            // 확정된 단가는 삭제 불가
            if ($price->is_final) {
                throw new BadRequestHttpException(__('error.pricing.finalized_cannot_delete'));
            }

            // 삭제 전 스냅샷 저장
            $beforeSnapshot = $price->toSnapshot();
            $this->createRevision($price, $beforeSnapshot, $userId, __('message.pricing.deleted'));

            $price->deleted_by = $userId;
            $price->save();
            $price->delete();
        });
    }

    /**
     * 단가 확정
     */
    public function finalize(int $id): Price
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $price = Price::query()
                ->where('tenant_id', $tenantId)
                ->find($id);

            if (! $price) {
                throw new NotFoundHttpException(__('error.not_found'));
            }

            if (! $price->canFinalize()) {
                throw new BadRequestHttpException(__('error.pricing.cannot_finalize'));
            }

            $beforeSnapshot = $price->toSnapshot();

            $price->update([
                'is_final' => true,
                'status' => 'finalized',
                'finalized_at' => now(),
                'finalized_by' => $userId,
                'updated_by' => $userId,
            ]);

            $price->refresh();

            // 확정 리비전 생성
            $this->createRevision($price, $beforeSnapshot, $userId, __('message.pricing.finalized'));

            return $price;
        });
    }

    /**
     * 품목별 단가 현황 조회
     * 여러 품목의 현재 유효한 단가를 한번에 조회
     */
    public function byItems(array $params): Collection
    {
        $tenantId = $this->tenantId();

        $items = $params['items'] ?? []; // [{item_type_code, item_id}, ...]
        $clientGroupId = $params['client_group_id'] ?? null;
        $date = $params['date'] ?? now()->toDateString();

        if (empty($items)) {
            return collect();
        }

        $results = collect();

        foreach ($items as $item) {
            $itemType = $item['item_type_code'] ?? null;
            $itemId = $item['item_id'] ?? null;

            if (! $itemType || ! $itemId) {
                continue;
            }

            // 고객그룹별 단가 우선 조회
            $price = null;
            if ($clientGroupId) {
                $price = Price::query()
                    ->where('tenant_id', $tenantId)
                    ->forItem($itemType, (int) $itemId)
                    ->forClientGroup((int) $clientGroupId)
                    ->validAt($date)
                    ->active()
                    ->orderByDesc('effective_from')
                    ->first();
            }

            // 기본 단가 fallback
            if (! $price) {
                $price = Price::query()
                    ->where('tenant_id', $tenantId)
                    ->forItem($itemType, (int) $itemId)
                    ->whereNull('client_group_id')
                    ->validAt($date)
                    ->active()
                    ->orderByDesc('effective_from')
                    ->first();
            }

            $results->push([
                'item_type_code' => $itemType,
                'item_id' => $itemId,
                'price' => $price,
                'has_price' => $price !== null,
            ]);
        }

        return $results;
    }

    /**
     * 리비전 이력 조회
     */
    public function revisions(int $priceId, array $params = []): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        // 단가 존재 확인
        $price = Price::query()
            ->where('tenant_id', $tenantId)
            ->find($priceId);

        if (! $price) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        $size = (int) ($params['size'] ?? 20);

        return PriceRevision::query()
            ->where('price_id', $priceId)
            ->with('changedByUser:id,name')
            ->orderByDesc('revision_number')
            ->paginate($size);
    }

    /**
     * 원가 조회 (수입검사 > 표준원가 fallback)
     */
    public function getCost(array $params): array
    {
        $tenantId = $this->tenantId();

        $itemType = $params['item_type_code'];
        $itemId = (int) $params['item_id'];
        $date = $params['date'] ?? now()->toDateString();

        $result = [
            'item_type_code' => $itemType,
            'item_id' => $itemId,
            'date' => $date,
            'cost_source' => 'not_found',
            'purchase_price' => null,
            'receipt_id' => null,
            'receipt_date' => null,
            'price_id' => null,
        ];

        // 1순위: 자재(is_material = true)인 경우 수입검사 입고단가 조회
        // common_codes의 attributes.is_material 플래그로 자재 여부 판단
        $isMaterial = DB::table('common_codes')
            ->where('code_group', 'item_type')
            ->where('code', $itemType)
            ->whereJsonContains('attributes->is_material', true)
            ->exists();

        if ($isMaterial) {
            $receipt = ItemReceipt::query()
                ->forItem($itemId)
                ->beforeDate($date)
                ->withPrice()
                ->orderByDesc('receipt_date')
                ->orderByDesc('id')
                ->first();

            if ($receipt && $receipt->purchase_price_excl_vat > 0) {
                $result['cost_source'] = 'receipt';
                $result['purchase_price'] = (float) $receipt->purchase_price_excl_vat;
                $result['receipt_id'] = $receipt->id;
                $result['receipt_date'] = $receipt->receipt_date;

                return $result;
            }
        }

        // 2순위: 표준원가 (prices 테이블)
        $price = Price::query()
            ->where('tenant_id', $tenantId)
            ->forItem($itemType, $itemId)
            ->whereNull('client_group_id')
            ->validAt($date)
            ->active()
            ->orderByDesc('effective_from')
            ->first();

        if ($price && $price->purchase_price > 0) {
            $result['cost_source'] = 'standard';
            $result['purchase_price'] = (float) $price->purchase_price;
            $result['price_id'] = $price->id;

            return $result;
        }

        // 3순위: 미등록
        return $result;
    }

    /**
     * 중복 체크
     */
    private function checkDuplicate(
        int $tenantId,
        string $itemType,
        int $itemId,
        ?int $clientGroupId,
        string $effectiveFrom,
        ?int $excludeId = null
    ): void {
        $query = Price::query()
            ->where('tenant_id', $tenantId)
            ->where('item_type_code', $itemType)
            ->where('item_id', $itemId)
            ->where('effective_from', $effectiveFrom);

        if ($clientGroupId) {
            $query->where('client_group_id', $clientGroupId);
        } else {
            $query->whereNull('client_group_id');
        }

        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        if ($query->exists()) {
            throw new BadRequestHttpException(__('error.duplicate_key'));
        }
    }

    /**
     * 기존 무기한 단가의 종료일 자동 설정
     */
    private function autoCloseExistingPrice(
        int $tenantId,
        string $itemType,
        int $itemId,
        ?int $clientGroupId,
        string $newEffectiveFrom
    ): void {
        $query = Price::query()
            ->where('tenant_id', $tenantId)
            ->where('item_type_code', $itemType)
            ->where('item_id', $itemId)
            ->whereNull('effective_to')
            ->where('effective_from', '<', $newEffectiveFrom);

        if ($clientGroupId) {
            $query->where('client_group_id', $clientGroupId);
        } else {
            $query->whereNull('client_group_id');
        }

        $existingPrice = $query->first();

        if ($existingPrice && ! $existingPrice->is_final) {
            $newEndDate = Carbon::parse($newEffectiveFrom)->subDay()->toDateString();
            $existingPrice->update([
                'effective_to' => $newEndDate,
                'updated_by' => $this->apiUserId(),
            ]);
        }
    }

    /**
     * 리비전 생성
     */
    private function createRevision(Price $price, ?array $beforeSnapshot, int $userId, ?string $reason = null): void
    {
        // 다음 리비전 번호 계산
        $nextRevision = PriceRevision::query()
            ->where('price_id', $price->id)
            ->max('revision_number') + 1;

        PriceRevision::create([
            'tenant_id' => $price->tenant_id,
            'price_id' => $price->id,
            'revision_number' => $nextRevision,
            'changed_at' => now(),
            'changed_by' => $userId,
            'change_reason' => $reason,
            'before_snapshot' => $beforeSnapshot,
            'after_snapshot' => $price->toSnapshot(),
        ]);
    }

    /**
     * 판매단가 재계산이 필요한지 확인
     */
    private function shouldRecalculateSalesPrice(array $data): bool
    {
        $recalcFields = ['purchase_price', 'processing_cost', 'loss_rate', 'margin_rate', 'rounding_rule', 'rounding_unit'];

        foreach ($recalcFields as $field) {
            if (array_key_exists($field, $data)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 단가 통계 조회
     */
    public function stats(): array
    {
        $tenantId = $this->tenantId();

        $baseQuery = Price::where('tenant_id', $tenantId);

        $total = (clone $baseQuery)->count();
        $draft = (clone $baseQuery)->where('status', 'draft')->count();
        $finalized = (clone $baseQuery)->where('status', 'finalized')->count();
        $expired = (clone $baseQuery)->where('status', 'expired')->count();

        return [
            'total' => $total,
            'draft' => $draft,
            'finalized' => $finalized,
            'expired' => $expired,
        ];
    }

    /**
     * 단가 일괄 삭제 (soft delete)
     */
    public function bulkDestroy(array $ids): int
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($ids, $tenantId, $userId) {
            $prices = Price::query()
                ->where('tenant_id', $tenantId)
                ->whereIn('id', $ids)
                ->get();

            if ($prices->isEmpty()) {
                throw new NotFoundHttpException(__('error.not_found'));
            }

            $deletedCount = 0;
            foreach ($prices as $price) {
                // 확정된 단가는 삭제 불가
                if ($price->is_final) {
                    continue;
                }

                // 삭제 전 스냅샷 저장
                $beforeSnapshot = $price->toSnapshot();
                $this->createRevision($price, $beforeSnapshot, $userId, __('message.pricing.deleted'));

                $price->deleted_by = $userId;
                $price->save();
                $price->delete();
                $deletedCount++;
            }

            return $deletedCount;
        });
    }
}
