<?php

namespace App\Services;

use App\Models\Orders\Order;
use App\Models\Production\WorkOrder;
use App\Models\Quote\Quote;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class OrderService extends Service
{
    /**
     * 목록 조회 (검색/필터링/페이징)
     */
    public function index(array $params)
    {
        $tenantId = $this->tenantId();

        $page = (int) ($params['page'] ?? 1);
        $size = (int) ($params['size'] ?? 20);
        $q = trim((string) ($params['q'] ?? ''));
        $status = $params['status'] ?? null;
        $orderType = $params['order_type'] ?? null;
        $clientId = $params['client_id'] ?? null;
        $dateFrom = $params['date_from'] ?? null;
        $dateTo = $params['date_to'] ?? null;
        $forWorkOrder = filter_var($params['for_work_order'] ?? false, FILTER_VALIDATE_BOOLEAN);

        $query = Order::query()
            ->where('tenant_id', $tenantId)
            ->with(['client:id,name', 'items', 'quote:id,quote_number']);

        // 작업지시 생성 가능한 수주만 필터링
        if ($forWorkOrder) {
            // 1. DRAFT(등록) 상태만 (생산지시 전)
            $query->where('status_code', Order::STATUS_DRAFT);

            // 2. 작업지시가 아직 없는 수주만
            $query->whereDoesntHave('workOrders');
        }

        // 검색어 (수주번호, 현장명, 거래처명)
        if ($q !== '') {
            $query->where(function ($qq) use ($q) {
                $qq->where('order_no', 'like', "%{$q}%")
                    ->orWhere('site_name', 'like', "%{$q}%")
                    ->orWhere('client_name', 'like', "%{$q}%");
            });
        }

        // 상태 필터 (for_work_order와 함께 사용시 무시)
        if ($status !== null && ! $forWorkOrder) {
            $query->where('status_code', $status);
        }

        // 주문유형 필터 (ORDER/PURCHASE)
        if ($orderType !== null) {
            $query->where('order_type_code', $orderType);
        }

        // 거래처 필터
        if ($clientId !== null) {
            $query->where('client_id', $clientId);
        }

        // 날짜 범위 (수주일 기준)
        if ($dateFrom !== null) {
            $query->where('received_at', '>=', $dateFrom);
        }
        if ($dateTo !== null) {
            $query->where('received_at', '<=', $dateTo);
        }

        $query->orderByDesc('created_at');

        return $query->paginate($size, ['*'], 'page', $page);
    }

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

        $counts = Order::where('tenant_id', $tenantId)
            ->select('status_code', DB::raw('count(*) as count'))
            ->groupBy('status_code')
            ->pluck('count', 'status_code')
            ->toArray();

        $amounts = Order::where('tenant_id', $tenantId)
            ->select('status_code', DB::raw('sum(total_amount) as total'))
            ->groupBy('status_code')
            ->pluck('total', 'status_code')
            ->toArray();

        return [
            'total' => array_sum($counts),
            'draft' => $counts[Order::STATUS_DRAFT] ?? 0,
            'confirmed' => $counts[Order::STATUS_CONFIRMED] ?? 0,
            'in_progress' => $counts[Order::STATUS_IN_PROGRESS] ?? 0,
            'completed' => $counts[Order::STATUS_COMPLETED] ?? 0,
            'cancelled' => $counts[Order::STATUS_CANCELLED] ?? 0,
            'total_amount' => array_sum($amounts),
            'confirmed_amount' => ($amounts[Order::STATUS_CONFIRMED] ?? 0) + ($amounts[Order::STATUS_IN_PROGRESS] ?? 0),
        ];
    }

    /**
     * 단건 조회
     */
    public function show(int $id)
    {
        $tenantId = $this->tenantId();

        $order = Order::where('tenant_id', $tenantId)
            ->with([
                'client:id,name,contact_person,phone,email,manager_name',
                'items' => fn ($q) => $q->orderBy('sort_order'),
                'quote:id,quote_number,site_name,calculation_inputs',
            ])
            ->find($id);

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

        return $order;
    }

    /**
     * 생성
     */
    public function store(array $data)
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            // 수주번호 자동 생성
            $data['order_no'] = $this->generateOrderNo($tenantId);
            $data['tenant_id'] = $tenantId;
            $data['created_by'] = $userId;
            $data['updated_by'] = $userId;

            // 기본 상태 설정
            $data['status_code'] = $data['status_code'] ?? Order::STATUS_DRAFT;
            $data['order_type_code'] = $data['order_type_code'] ?? Order::TYPE_ORDER;

            $items = $data['items'] ?? [];
            unset($data['items']);

            $order = Order::create($data);

            // 품목 저장
            foreach ($items as $index => $item) {
                $item['tenant_id'] = $tenantId;
                $item['serial_no'] = $index + 1; // 1부터 시작하는 순번
                $item['sort_order'] = $index;
                $this->calculateItemAmounts($item);
                $order->items()->create($item);
            }

            // 합계 재계산
            $order->refresh();
            $order->recalculateTotals()->save();

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

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

        $order = Order::where('tenant_id', $tenantId)->find($id);
        if (! $order) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // 완료/취소 상태에서는 수정 불가
        if (in_array($order->status_code, [Order::STATUS_COMPLETED, Order::STATUS_CANCELLED])) {
            throw new BadRequestHttpException(__('error.order.cannot_update_completed'));
        }

        return DB::transaction(function () use ($order, $data, $tenantId, $userId) {
            $data['updated_by'] = $userId;

            $items = $data['items'] ?? null;
            unset($data['items'], $data['order_no']); // 번호 변경 불가

            $order->update($data);

            // 품목 교체 (있는 경우)
            if ($items !== null) {
                $order->items()->delete();
                foreach ($items as $index => $item) {
                    $item['tenant_id'] = $tenantId;
                    $item['serial_no'] = $index + 1; // 1부터 시작하는 순번
                    $item['sort_order'] = $index;
                    $this->calculateItemAmounts($item);
                    $order->items()->create($item);
                }

                // 합계 재계산
                $order->refresh();
                $order->recalculateTotals()->save();
            }

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

    /**
     * 삭제
     */
    public function destroy(int $id)
    {
        $tenantId = $this->tenantId();

        $order = Order::where('tenant_id', $tenantId)->find($id);
        if (! $order) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // 진행 중이거나 완료된 수주는 삭제 불가
        if (in_array($order->status_code, [
            Order::STATUS_IN_PROGRESS,
            Order::STATUS_COMPLETED,
        ])) {
            throw new BadRequestHttpException(__('error.order.cannot_delete_in_progress'));
        }

        $order->deleted_by = $this->apiUserId();
        $order->save();
        $order->delete();

        return 'success';
    }

    /**
     * 상태 변경
     */
    public function updateStatus(int $id, string $status)
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $order = Order::where('tenant_id', $tenantId)->find($id);
        if (! $order) {
            throw new NotFoundHttpException(__('error.not_found'));
        }

        // 상태 유효성 검증
        $validStatuses = [
            Order::STATUS_DRAFT,
            Order::STATUS_CONFIRMED,
            Order::STATUS_IN_PROGRESS,
            Order::STATUS_COMPLETED,
            Order::STATUS_CANCELLED,
        ];

        if (! in_array($status, $validStatuses)) {
            throw new BadRequestHttpException(__('error.invalid_status'));
        }

        // 상태 전환 규칙 검증
        $this->validateStatusTransition($order->status_code, $status);

        $order->status_code = $status;
        $order->updated_by = $userId;
        $order->save();

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

    /**
     * 상태 전환 규칙 검증
     */
    private function validateStatusTransition(string $from, string $to): void
    {
        $allowedTransitions = [
            Order::STATUS_DRAFT => [Order::STATUS_CONFIRMED, Order::STATUS_CANCELLED],
            Order::STATUS_CONFIRMED => [Order::STATUS_IN_PROGRESS, Order::STATUS_CANCELLED],
            Order::STATUS_IN_PROGRESS => [Order::STATUS_COMPLETED, Order::STATUS_CANCELLED],
            Order::STATUS_COMPLETED => [], // 완료 상태에서는 변경 불가
            Order::STATUS_CANCELLED => [Order::STATUS_DRAFT], // 취소에서 임시저장으로만 복구 가능
        ];

        if (! in_array($to, $allowedTransitions[$from] ?? [])) {
            throw new BadRequestHttpException(__('error.order.invalid_status_transition'));
        }
    }

    /**
     * 품목 금액 계산
     */
    private function calculateItemAmounts(array &$item): void
    {
        $quantity = (float) ($item['quantity'] ?? 0);
        $unitPrice = (float) ($item['unit_price'] ?? 0);

        $item['supply_amount'] = $quantity * $unitPrice;
        $item['tax_amount'] = round($item['supply_amount'] * 0.1, 2);
        $item['total_amount'] = $item['supply_amount'] + $item['tax_amount'];
    }

    /**
     * 수주번호 자동 생성
     */
    private function generateOrderNo(int $tenantId): string
    {
        $prefix = 'ORD';
        $date = now()->format('Ymd');

        // 오늘 날짜 기준 마지막 번호 조회
        $lastNo = Order::withoutGlobalScopes()
            ->where('tenant_id', $tenantId)
            ->where('order_no', 'like', "{$prefix}{$date}%")
            ->orderByDesc('order_no')
            ->value('order_no');

        if ($lastNo) {
            $seq = (int) substr($lastNo, -4) + 1;
        } else {
            $seq = 1;
        }

        return sprintf('%s%s%04d', $prefix, $date, $seq);
    }

    /**
     * 견적에서 수주 생성
     */
    public function createFromQuote(int $quoteId, array $data = [])
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 견적 조회
        $quote = Quote::where('tenant_id', $tenantId)
            ->with(['items', 'client'])
            ->find($quoteId);

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

        // 이미 수주가 생성된 견적인지 확인
        $existingOrder = Order::where('tenant_id', $tenantId)
            ->where('quote_id', $quoteId)
            ->first();

        if ($existingOrder) {
            throw new BadRequestHttpException(__('error.order.already_created_from_quote'));
        }

        return DB::transaction(function () use ($quote, $data, $tenantId, $userId) {
            // 수주번호 생성
            $orderNo = $this->generateOrderNo($tenantId);

            // Order 모델의 createFromQuote 사용
            $order = Order::createFromQuote($quote, $orderNo);
            $order->created_by = $userId;
            $order->updated_by = $userId;

            // 추가 데이터 병합 (납품일, 메모 등)
            if (! empty($data['delivery_date'])) {
                $order->delivery_date = $data['delivery_date'];
            }
            if (! empty($data['memo'])) {
                $order->memo = $data['memo'];
            }

            $order->save();

            // 견적 품목을 수주 품목으로 변환
            foreach ($quote->items as $index => $quoteItem) {
                $order->items()->create([
                    'tenant_id' => $tenantId,
                    'serial_no' => $index + 1, // 1부터 시작하는 순번
                    'item_id' => $quoteItem->item_id,
                    'item_name' => $quoteItem->item_name,
                    'specification' => $quoteItem->specification,
                    'quantity' => $quoteItem->calculated_quantity,
                    'unit' => $quoteItem->unit,
                    'unit_price' => $quoteItem->unit_price,
                    'supply_amount' => $quoteItem->total_price,
                    'tax_amount' => round($quoteItem->total_price * 0.1, 2),
                    'total_amount' => round($quoteItem->total_price * 1.1, 2),
                    'sort_order' => $index,
                ]);
            }

            // 합계 재계산
            $order->refresh();
            $order->recalculateTotals()->save();

            // 견적 상태를 '수주전환완료'로 변경
            $quote->update([
                'status' => Quote::STATUS_CONVERTED,
                'order_id' => $order->id,
                'updated_by' => $userId,
            ]);

            return $order->load(['client:id,name', 'items', 'quote:id,quote_number']);
        });
    }

    /**
     * 생산지시 생성 (공정별 작업지시 다중 생성)
     */
    public function createProductionOrder(int $orderId, array $data)
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 수주 조회
        $order = Order::where('tenant_id', $tenantId)
            ->with('items')
            ->find($orderId);

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

        // 상태 확인 (CONFIRMED 상태에서만 생산지시 가능)
        if ($order->status_code !== Order::STATUS_CONFIRMED) {
            throw new BadRequestHttpException(__('error.order.must_be_confirmed_for_production'));
        }

        // 이미 생산지시가 존재하는지 확인
        $existingWorkOrder = WorkOrder::where('tenant_id', $tenantId)
            ->where('sales_order_id', $orderId)
            ->first();

        if ($existingWorkOrder) {
            throw new BadRequestHttpException(__('error.order.production_order_already_exists'));
        }

        // process_ids 배열 또는 단일 process_id 처리
        $processIds = $data['process_ids'] ?? [];
        if (empty($processIds) && ! empty($data['process_id'])) {
            $processIds = [$data['process_id']];
        }

        // 공정이 없으면 null로 하나만 생성
        if (empty($processIds)) {
            $processIds = [null];
        }

        return DB::transaction(function () use ($order, $data, $tenantId, $userId, $processIds) {
            $workOrders = [];

            foreach ($processIds as $processId) {
                // 작업지시번호 생성
                $workOrderNo = $this->generateWorkOrderNo($tenantId);

                // 작업지시 생성
                $workOrder = WorkOrder::create([
                    'tenant_id' => $tenantId,
                    'work_order_no' => $workOrderNo,
                    'sales_order_id' => $order->id,
                    'project_name' => $order->site_name ?? $order->client_name,
                    'process_id' => $processId,
                    'status' => WorkOrder::STATUS_PENDING,
                    'assignee_id' => $data['assignee_id'] ?? null,
                    'team_id' => $data['team_id'] ?? null,
                    'scheduled_date' => $data['scheduled_date'] ?? $order->delivery_date,
                    'memo' => $data['memo'] ?? null,
                    'is_active' => true,
                    'created_by' => $userId,
                    'updated_by' => $userId,
                ]);

                $workOrders[] = $workOrder->load(['assignee:id,name', 'team:id,name', 'process:id,process_name,process_code']);
            }

            // 수주 상태를 IN_PROGRESS로 변경
            $order->status_code = Order::STATUS_IN_PROGRESS;
            $order->updated_by = $userId;
            $order->save();

            return [
                'work_orders' => $workOrders,
                'work_order' => $workOrders[0] ?? null, // 하위 호환성
                'order' => $order->load(['client:id,name', 'items']),
            ];
        });
    }

    /**
     * 작업지시번호 자동 생성
     */
    private function generateWorkOrderNo(int $tenantId): string
    {
        $prefix = 'WO';
        $date = now()->format('Ymd');

        $lastNo = WorkOrder::withoutGlobalScopes()
            ->where('tenant_id', $tenantId)
            ->where('work_order_no', 'like', "{$prefix}{$date}%")
            ->orderByDesc('work_order_no')
            ->value('work_order_no');

        if ($lastNo) {
            $seq = (int) substr($lastNo, -4) + 1;
        } else {
            $seq = 1;
        }

        return sprintf('%s%s%04d', $prefix, $date, $seq);
    }

    /**
     * 수주확정 되돌리기 (수주등록 상태로 변경)
     */
    public function revertOrderConfirmation(int $orderId): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 수주 조회
        $order = Order::where('tenant_id', $tenantId)
            ->find($orderId);

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

        // 수주확정 상태에서만 되돌리기 가능
        if ($order->status_code !== Order::STATUS_CONFIRMED) {
            throw new BadRequestHttpException(__('error.order.cannot_revert_not_confirmed'));
        }

        // 상태 변경
        $previousStatus = $order->status_code;
        $order->status_code = Order::STATUS_DRAFT;
        $order->updated_by = $userId;
        $order->save();

        return [
            'order' => $order->load(['client:id,name', 'items']),
            'previous_status' => $previousStatus,
        ];
    }

    /**
     * 생산지시 되돌리기 (작업지시 및 관련 데이터 삭제)
     */
    public function revertProductionOrder(int $orderId): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 수주 조회
        $order = Order::where('tenant_id', $tenantId)
            ->find($orderId);

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

        // 완료된 수주는 되돌리기 불가
        if ($order->status_code === Order::STATUS_COMPLETED) {
            throw new BadRequestHttpException(__('error.order.cannot_revert_completed'));
        }

        return DB::transaction(function () use ($order, $tenantId, $userId) {
            // 관련 작업지시 ID 조회
            $workOrderIds = WorkOrder::where('tenant_id', $tenantId)
                ->where('sales_order_id', $order->id)
                ->pluck('id')
                ->toArray();

            $deletedCounts = [
                'work_results' => 0,
                'work_order_items' => 0,
                'work_orders' => 0,
            ];

            if (count($workOrderIds) > 0) {
                // 1. 작업결과 삭제
                $deletedCounts['work_results'] = DB::table('work_results')
                    ->whereIn('work_order_id', $workOrderIds)
                    ->delete();

                // 2. 작업지시 품목 삭제
                $deletedCounts['work_order_items'] = DB::table('work_order_items')
                    ->whereIn('work_order_id', $workOrderIds)
                    ->delete();

                // 3. 작업지시 삭제
                $deletedCounts['work_orders'] = WorkOrder::whereIn('id', $workOrderIds)
                    ->delete();
            }

            // 4. 수주 상태를 CONFIRMED로 되돌리기
            $previousStatus = $order->status_code;
            $order->status_code = Order::STATUS_CONFIRMED;
            $order->updated_by = $userId;
            $order->save();

            return [
                'order' => $order->load(['client:id,name', 'items']),
                'deleted_counts' => $deletedCounts,
                'previous_status' => $previousStatus,
            ];
        });
    }
}
