<?php

namespace App\Services\Estimate;

use App\Models\Estimate\Estimate;
use App\Models\Estimate\EstimateItem;
use App\Services\Calculation\CalculationEngine;
use App\Services\ModelSet\ModelSetService;
use App\Services\Pricing\PricingService;
use App\Services\Service;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class EstimateService extends Service
{
    protected ModelSetService $modelSetService;

    protected CalculationEngine $calculationEngine;

    protected PricingService $pricingService;

    public function __construct(
        ModelSetService $modelSetService,
        CalculationEngine $calculationEngine,
        PricingService $pricingService
    ) {
        $this->modelSetService = $modelSetService;
        $this->calculationEngine = $calculationEngine;
        $this->pricingService = $pricingService;
    }

    /**
     * 견적 목록 조회
     */
    public function getEstimates(array $filters = []): LengthAwarePaginator
    {
        $query = Estimate::with(['modelSet', 'items'])
            ->where('tenant_id', $this->tenantId());

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

        if (! empty($filters['customer_name'])) {
            $query->where('customer_name', 'like', '%'.$filters['customer_name'].'%');
        }

        if (! empty($filters['model_set_id'])) {
            $query->where('model_set_id', $filters['model_set_id']);
        }

        if (! empty($filters['date_from'])) {
            $query->whereDate('created_at', '>=', $filters['date_from']);
        }

        if (! empty($filters['date_to'])) {
            $query->whereDate('created_at', '<=', $filters['date_to']);
        }

        if (! empty($filters['search'])) {
            $searchTerm = $filters['search'];
            $query->where(function ($q) use ($searchTerm) {
                $q->where('estimate_name', 'like', '%'.$searchTerm.'%')
                    ->orWhere('estimate_no', 'like', '%'.$searchTerm.'%')
                    ->orWhere('project_name', 'like', '%'.$searchTerm.'%');
            });
        }

        return $query->orderBy('created_at', 'desc')
            ->paginate($filters['per_page'] ?? 20);
    }

    /**
     * 견적 상세 조회
     */
    public function getEstimateDetail($estimateId): array
    {
        $estimate = Estimate::with(['modelSet.fields', 'items'])
            ->where('tenant_id', $this->tenantId())
            ->findOrFail($estimateId);

        return [
            'estimate' => $estimate,
            'model_set_schema' => $this->modelSetService->getModelSetCategoryFields($estimate->model_set_id),
            'calculation_summary' => $this->summarizeCalculations($estimate),
        ];
    }

    /**
     * 견적 생성
     */
    public function createEstimate(array $data): array
    {
        return DB::transaction(function () use ($data) {
            // 견적번호 생성
            $estimateNo = Estimate::generateEstimateNo($this->tenantId());

            // 모델셋 기반 BOM 계산
            $bomCalculation = $this->modelSetService->calculateModelSetBom(
                $data['model_set_id'],
                $data['parameters']
            );

            // 견적 생성
            $estimate = Estimate::create([
                'tenant_id' => $this->tenantId(),
                'model_set_id' => $data['model_set_id'],
                'estimate_no' => $estimateNo,
                'estimate_name' => $data['estimate_name'],
                'customer_name' => $data['customer_name'] ?? null,
                'project_name' => $data['project_name'] ?? null,
                'parameters' => $data['parameters'],
                'calculated_results' => $bomCalculation['calculated_values'] ?? [],
                'bom_data' => $bomCalculation,
                'total_amount' => 0, // 항목 생성 후 재계산
                'notes' => $data['notes'] ?? null,
                'valid_until' => now()->addDays(30), // 기본 30일 유효
                'created_by' => $this->apiUserId(),
            ]);

            // 견적 항목 생성 (BOM 기반) + 가격 계산
            if (! empty($bomCalculation['bom_items'])) {
                $totalAmount = $this->createEstimateItems(
                    $estimate,
                    $bomCalculation['bom_items'],
                    $data['client_id'] ?? null
                );

                // 총액 업데이트
                $estimate->update(['total_amount' => $totalAmount]);
            }

            return $this->getEstimateDetail($estimate->id);
        });
    }

    /**
     * 견적 수정
     */
    public function updateEstimate($estimateId, array $data): array
    {
        return DB::transaction(function () use ($estimateId, $data) {
            $estimate = Estimate::where('tenant_id', $this->tenantId())
                ->findOrFail($estimateId);

            // 파라미터가 변경되면 재계산
            if (isset($data['parameters'])) {
                $bomCalculation = $this->modelSetService->calculateModelSetBom(
                    $estimate->model_set_id,
                    $data['parameters']
                );

                $data['calculated_results'] = $bomCalculation['calculated_values'] ?? [];
                $data['bom_data'] = $bomCalculation;

                // 기존 견적 항목 삭제 후 재생성
                $estimate->items()->delete();
                if (! empty($bomCalculation['bom_items'])) {
                    $totalAmount = $this->createEstimateItems(
                        $estimate,
                        $bomCalculation['bom_items'],
                        $data['client_id'] ?? null
                    );
                    $data['total_amount'] = $totalAmount;
                }
            }

            $estimate->update([
                ...$data,
                'updated_by' => $this->apiUserId(),
            ]);

            return $this->getEstimateDetail($estimate->id);
        });
    }

    /**
     * 견적 삭제
     */
    public function deleteEstimate($estimateId): void
    {
        DB::transaction(function () use ($estimateId) {
            $estimate = Estimate::where('tenant_id', $this->tenantId())
                ->findOrFail($estimateId);

            // 진행 중인 견적은 삭제 불가
            if (in_array($estimate->status, ['SENT', 'APPROVED'])) {
                throw new \Exception(__('error.estimate.cannot_delete_sent_or_approved'));
            }

            $estimate->update(['deleted_by' => $this->apiUserId()]);
            $estimate->delete();
        });
    }

    /**
     * 견적 복제
     */
    public function cloneEstimate($estimateId, array $data): array
    {
        return DB::transaction(function () use ($estimateId, $data) {
            $originalEstimate = Estimate::with('items')
                ->where('tenant_id', $this->tenantId())
                ->findOrFail($estimateId);

            // 새 견적번호 생성
            $newEstimateNo = Estimate::generateEstimateNo($this->tenantId());

            // 견적 복제
            $newEstimate = Estimate::create([
                'tenant_id' => $this->tenantId(),
                'model_set_id' => $originalEstimate->model_set_id,
                'estimate_no' => $newEstimateNo,
                'estimate_name' => $data['estimate_name'],
                'customer_name' => $data['customer_name'] ?? $originalEstimate->customer_name,
                'project_name' => $data['project_name'] ?? $originalEstimate->project_name,
                'parameters' => $originalEstimate->parameters,
                'calculated_results' => $originalEstimate->calculated_results,
                'bom_data' => $originalEstimate->bom_data,
                'total_amount' => $originalEstimate->total_amount,
                'notes' => $data['notes'] ?? $originalEstimate->notes,
                'valid_until' => now()->addDays(30),
                'created_by' => $this->apiUserId(),
            ]);

            // 견적 항목 복제
            foreach ($originalEstimate->items as $item) {
                EstimateItem::create([
                    'tenant_id' => $this->tenantId(),
                    'estimate_id' => $newEstimate->id,
                    'sequence' => $item->sequence,
                    'item_name' => $item->item_name,
                    'item_description' => $item->item_description,
                    'parameters' => $item->parameters,
                    'calculated_values' => $item->calculated_values,
                    'unit_price' => $item->unit_price,
                    'quantity' => $item->quantity,
                    'total_price' => $item->total_price,
                    'bom_components' => $item->bom_components,
                    'notes' => $item->notes,
                    'created_by' => $this->apiUserId(),
                ]);
            }

            return $this->getEstimateDetail($newEstimate->id);
        });
    }

    /**
     * 견적 상태 변경
     */
    public function changeEstimateStatus($estimateId, string $status, ?string $notes = null): array
    {
        $estimate = Estimate::where('tenant_id', $this->tenantId())
            ->findOrFail($estimateId);

        $validTransitions = [
            'DRAFT' => ['SENT', 'REJECTED'],
            'SENT' => ['APPROVED', 'REJECTED', 'EXPIRED'],
            'APPROVED' => ['EXPIRED'],
            'REJECTED' => ['DRAFT'],
            'EXPIRED' => ['DRAFT'],
        ];

        if (! in_array($status, $validTransitions[$estimate->status] ?? [])) {
            throw new \Exception(__('error.estimate.invalid_status_transition'));
        }

        $estimate->update([
            'status' => $status,
            'notes' => $notes ? ($estimate->notes."\n\n".$notes) : $estimate->notes,
            'updated_by' => $this->apiUserId(),
        ]);

        return $this->getEstimateDetail($estimate->id);
    }

    /**
     * 동적 견적 폼 스키마 조회
     */
    public function getEstimateFormSchema($modelSetId): array
    {
        $parameters = $this->modelSetService->getEstimateParameters($modelSetId);

        return [
            'model_set' => $parameters['category'],
            'form_schema' => [
                'input_fields' => $parameters['input_fields'],
                'calculated_fields' => $parameters['calculated_fields'],
            ],
            'calculation_schema' => $parameters['calculation_schema'],
        ];
    }

    /**
     * 견적 파라미터 미리보기 계산
     */
    public function previewCalculation($modelSetId, array $parameters): array
    {
        return $this->modelSetService->calculateModelSetBom($modelSetId, $parameters);
    }

    /**
     * 견적 항목 생성 (가격 계산 포함)
     *
     * @return float 총 견적 금액
     */
    protected function createEstimateItems(Estimate $estimate, array $bomItems, ?int $clientId = null): float
    {
        $totalAmount = 0;
        $warnings = [];

        foreach ($bomItems as $index => $bomItem) {
            $quantity = $bomItem['quantity'] ?? 1;
            $unitPrice = 0;

            // 가격 조회 (item_id와 item_type이 있는 경우)
            if (isset($bomItem['item_id']) && isset($bomItem['item_type'])) {
                $priceResult = $this->pricingService->getItemPrice(
                    $bomItem['item_type'], // 'PRODUCT' or 'MATERIAL'
                    $bomItem['item_id'],
                    $clientId,
                    now()->format('Y-m-d')
                );

                $unitPrice = $priceResult['price'] ?? 0;

                if ($priceResult['warning']) {
                    $warnings[] = $priceResult['warning'];
                }
            }

            $totalPrice = $unitPrice * $quantity;
            $totalAmount += $totalPrice;

            EstimateItem::create([
                'tenant_id' => $this->tenantId(),
                'estimate_id' => $estimate->id,
                'sequence' => $index + 1,
                'item_name' => $bomItem['name'] ?? '견적 항목 '.($index + 1),
                'item_description' => $bomItem['description'] ?? '',
                'parameters' => $bomItem['parameters'] ?? [],
                'calculated_values' => $bomItem['calculated_values'] ?? [],
                'unit_price' => $unitPrice,
                'quantity' => $quantity,
                'total_price' => $totalPrice,
                'bom_components' => $bomItem['components'] ?? [],
                'created_by' => $this->apiUserId(),
            ]);
        }

        // 가격 경고가 있으면 로그 기록
        if (! empty($warnings)) {
            \Log::warning('견적 가격 조회 경고', [
                'estimate_id' => $estimate->id,
                'warnings' => $warnings,
            ]);
        }

        return $totalAmount;
    }

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

        $stats = Estimate::query()
            ->where('tenant_id', $tenantId)
            ->selectRaw("
                COUNT(*) as total,
                SUM(CASE WHEN status = 'DRAFT' THEN 1 ELSE 0 END) as draft,
                SUM(CASE WHEN status = 'SENT' THEN 1 ELSE 0 END) as sent,
                SUM(CASE WHEN status = 'APPROVED' THEN 1 ELSE 0 END) as approved,
                SUM(CASE WHEN status = 'REJECTED' THEN 1 ELSE 0 END) as rejected,
                SUM(CASE WHEN status = 'EXPIRED' THEN 1 ELSE 0 END) as expired,
                SUM(total_amount) as total_amount
            ")
            ->first();

        return [
            'total' => (int) $stats->total,
            'draft' => (int) $stats->draft,
            'sent' => (int) $stats->sent,
            'approved' => (int) $stats->approved,
            'rejected' => (int) $stats->rejected,
            'expired' => (int) $stats->expired,
            'total_amount' => (float) ($stats->total_amount ?? 0),
        ];
    }

    /**
     * 계산 결과 요약
     */
    protected function summarizeCalculations(Estimate $estimate): array
    {
        $summary = [
            'total_items' => $estimate->items->count(),
            'total_amount' => $estimate->total_amount,
            'key_calculations' => [],
        ];

        // 주요 계산 결과 추출
        if (! empty($estimate->calculated_results)) {
            $results = $estimate->calculated_results;

            if (isset($results['W1'], $results['H1'])) {
                $summary['key_calculations']['제작사이즈'] = $results['W1'].' × '.$results['H1'].' mm';
            }

            if (isset($results['weight'])) {
                $summary['key_calculations']['중량'] = $results['weight'].' kg';
            }

            if (isset($results['area'])) {
                $summary['key_calculations']['면적'] = $results['area'].' ㎡';
            }

            if (isset($results['bracket_size'])) {
                $summary['key_calculations']['모터브라켓'] = $results['bracket_size'];
            }
        }

        return $summary;
    }
}
