<?php

namespace App\Services;

use App\Models\Orders\Order;
use App\Models\Production\WorkOrder;
use App\Models\Production\WorkOrderMaterialInput;
use App\Models\Qualitys\Inspection;
use App\Models\Qualitys\QualityDocument;
use App\Models\Qualitys\QualityDocumentLocation;
use App\Models\Qualitys\QualityDocumentOrder;
use App\Models\Tenants\Shipment;
use App\Models\Tenants\StockLot;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class QmsLotAuditService extends Service
{
    /**
     * 품질관리서 목록 (로트 추적 심사용)
     * completed 상태의 품질관리서를 PerformanceReport 기반으로 필터링
     */
    public function index(array $params): array
    {
        $query = QualityDocument::with([
            'documentOrders.order.nodes' => fn ($q) => $q->whereNull('parent_id'),
            'documentOrders.order.nodes.items.item',
            'locations',
            'performanceReport',
        ])
            ->where('status', QualityDocument::STATUS_COMPLETED);

        // 연도 필터
        if (! empty($params['year'])) {
            $year = (int) $params['year'];
            $query->where(function ($q) use ($year) {
                $q->whereHas('performanceReport', fn ($pr) => $pr->where('year', $year))
                    ->orWhereDoesntHave('performanceReport');
            });
        }

        // 분기 필터
        if (! empty($params['quarter'])) {
            $quarter = (int) $params['quarter'];
            $query->whereHas('performanceReport', fn ($pr) => $pr->where('quarter', $quarter));
        }

        // 검색어 필터
        if (! empty($params['q'])) {
            $term = trim($params['q']);
            $query->where(function ($q) use ($term) {
                $q->where('quality_doc_number', 'like', "%{$term}%")
                    ->orWhere('site_name', 'like', "%{$term}%");
            });
        }

        $query->orderByDesc('id');
        $perPage = (int) ($params['per_page'] ?? 20);
        $paginated = $query->paginate($perPage);

        $items = $paginated->getCollection()->map(fn ($doc) => $this->transformReportToFrontend($doc));

        return [
            'items' => $items,
            'current_page' => $paginated->currentPage(),
            'last_page' => $paginated->lastPage(),
            'per_page' => $paginated->perPage(),
            'total' => $paginated->total(),
        ];
    }

    /**
     * 품질관리서 상세 — 수주/개소 목록 (RouteItem[])
     */
    public function show(int $id): array
    {
        $doc = QualityDocument::with([
            'documentOrders.order',
            'documentOrders.locations.orderItem',
        ])->findOrFail($id);

        return $doc->documentOrders->map(fn ($docOrder) => $this->transformRouteToFrontend($docOrder, $doc))->values()->all();
    }

    /**
     * 수주 루트별 8종 서류 목록 (Document[])
     */
    public function routeDocuments(int $qualityDocumentOrderId): array
    {
        $docOrder = QualityDocumentOrder::with([
            'order.workOrders.process',
            'locations',
            'qualityDocument',
        ])->findOrFail($qualityDocumentOrderId);

        $order = $docOrder->order;
        $qualityDoc = $docOrder->qualityDocument;
        $workOrders = $order->workOrders;

        $documents = [];

        // 1. 수입검사 성적서 (IQC): WorkOrderMaterialInput → StockLot → lot_no → Inspection(IQC)
        $investedLotIds = WorkOrderMaterialInput::whereIn('work_order_id', $workOrders->pluck('id'))
            ->pluck('stock_lot_id')
            ->unique();

        $investedLotNos = StockLot::whereIn('id', $investedLotIds)
            ->whereNotNull('lot_no')
            ->pluck('lot_no')
            ->unique();

        $iqcInspections = Inspection::where('inspection_type', 'IQC')
            ->whereIn('lot_no', $investedLotNos)
            ->where('status', 'completed')
            ->get();

        $documents[] = $this->formatDocument('import', '수입검사 성적서', $iqcInspections);

        // 2. 수주서
        $documents[] = $this->formatDocument('order', '수주서', collect([$order]));

        // 3. 작업일지 (subType: process.process_name 기반)
        $documents[] = $this->formatDocumentWithSubType('log', '작업일지', $workOrders);

        // 4. 중간검사 성적서 (PQC)
        $pqcInspections = Inspection::where('inspection_type', 'PQC')
            ->whereIn('work_order_id', $workOrders->pluck('id'))
            ->where('status', 'completed')
            ->with('workOrder.process')
            ->get();

        $documents[] = $this->formatDocumentWithSubType('report', '중간검사 성적서', $pqcInspections, 'workOrder');

        // 5. 납품확인서
        $shipments = $order->shipments()->get();
        $documents[] = $this->formatDocument('confirmation', '납품확인서', $shipments);

        // 6. 출고증
        $documents[] = $this->formatDocument('shipping', '출고증', $shipments);

        // 7. 제품검사 성적서
        $locationsWithDoc = $docOrder->locations->filter(fn ($loc) => $loc->document_id);
        $documents[] = $this->formatDocument('product', '제품검사 성적서', $locationsWithDoc);

        // 8. 품질관리서
        $documents[] = $this->formatDocument('quality', '품질관리서', collect([$qualityDoc]));

        return $documents;
    }

    /**
     * 서류 상세 조회 (2단계 로딩 — 모달 렌더링용)
     */
    public function documentDetail(string $type, int $id): array
    {
        return match ($type) {
            'import' => $this->getInspectionDetail($id, 'IQC'),
            'order' => $this->getOrderDetail($id),
            'log' => $this->getWorkOrderLogDetail($id),
            'report' => $this->getInspectionDetail($id, 'PQC'),
            'confirmation', 'shipping' => $this->getShipmentDetail($id),
            'product' => $this->getLocationDetail($id),
            'quality' => $this->getQualityDocDetail($id),
            default => throw new NotFoundHttpException(__('error.not_found')),
        };
    }

    /**
     * 개소별 로트 심사 확인 토글
     */
    public function confirm(int $locationId, array $data): array
    {
        $location = QualityDocumentLocation::findOrFail($locationId);
        $confirmed = (bool) $data['confirmed'];
        $userId = $this->apiUserId();

        DB::transaction(function () use ($location, $confirmed, $userId) {
            $location->lockForUpdate();

            $options = $location->options ?? [];
            $options['lot_audit_confirmed'] = $confirmed;
            $options['lot_audit_confirmed_at'] = $confirmed ? now()->toIso8601String() : null;
            $options['lot_audit_confirmed_by'] = $confirmed ? $userId : null;
            $location->options = $options;
            $location->save();
        });

        $location->refresh();

        return [
            'id' => (string) $location->id,
            'name' => $this->buildLocationName($location),
            'location' => $this->buildLocationCode($location),
            'is_completed' => (bool) data_get($location->options, 'lot_audit_confirmed', false),
        ];
    }

    // ===== Private: Transform Methods =====

    private function transformReportToFrontend(QualityDocument $doc): array
    {
        $performanceReport = $doc->performanceReport;
        $confirmedCount = $doc->locations->filter(function ($loc) {
            return data_get($loc->options, 'lot_audit_confirmed', false);
        })->count();

        return [
            'id' => (string) $doc->id,
            'code' => $doc->quality_doc_number,
            'site_name' => $doc->site_name,
            'item' => $this->getFgProductName($doc),
            'route_count' => $confirmedCount,
            'total_routes' => $doc->locations->count(),
            'quarter' => $performanceReport
                ? $performanceReport->year.'년 '.$performanceReport->quarter.'분기'
                : '',
            'year' => $performanceReport?->year ?? now()->year,
            'quarter_num' => $performanceReport?->quarter ?? 0,
        ];
    }

    /**
     * BOM 최상위(FG) 제품명 추출
     * Order → root OrderNode(parent_id=null) → 대표 OrderItem → Item(FG).name
     */
    private function getFgProductName(QualityDocument $doc): string
    {
        $firstDocOrder = $doc->documentOrders->first();
        if (! $firstDocOrder) {
            return '';
        }

        $order = $firstDocOrder->order;
        if (! $order) {
            return '';
        }

        // eager loaded with whereNull('parent_id') filter
        $rootNode = $order->nodes->first();
        if (! $rootNode) {
            return '';
        }

        $representativeItem = $rootNode->items->first();

        return $representativeItem?->item?->name ?? '';
    }

    private function transformRouteToFrontend(QualityDocumentOrder $docOrder, QualityDocument $qualityDoc): array
    {
        return [
            'id' => (string) $docOrder->id,
            'code' => $docOrder->order->order_no,
            'date' => $docOrder->order->received_at?->toDateString(),
            'site' => $docOrder->order->site_name ?? '',
            'location_count' => $docOrder->locations->count(),
            'sub_items' => $docOrder->locations->values()->map(fn ($loc, $idx) => [
                'id' => (string) $loc->id,
                'name' => $qualityDoc->quality_doc_number.'-'.str_pad($idx + 1, 2, '0', STR_PAD_LEFT),
                'location' => $this->buildLocationCode($loc),
                'is_completed' => (bool) data_get($loc->options, 'lot_audit_confirmed', false),
            ])->all(),
        ];
    }

    private function buildLocationName(QualityDocumentLocation $location): string
    {
        $qualityDoc = $location->qualityDocument;
        if (! $qualityDoc) {
            return '';
        }

        // location의 순번을 구하기 위해 같은 문서의 location 목록 조회
        $locations = QualityDocumentLocation::where('quality_document_id', $qualityDoc->id)
            ->orderBy('id')
            ->pluck('id');

        $index = $locations->search($location->id);

        return $qualityDoc->quality_doc_number.'-'.str_pad(($index !== false ? $index + 1 : 1), 2, '0', STR_PAD_LEFT);
    }

    private function buildLocationCode(QualityDocumentLocation $location): string
    {
        $orderItem = $location->orderItem;
        if (! $orderItem) {
            return '';
        }

        return trim(($orderItem->floor_code ?? '').' '.($orderItem->symbol_code ?? ''));
    }

    // ===== Private: Document Format Helpers =====

    private function formatDocument(string $type, string $title, $collection): array
    {
        return [
            'id' => $type,
            'type' => $type,
            'title' => $title,
            'count' => $collection->count(),
            'items' => $collection->values()->map(fn ($item) => $this->formatDocumentItem($type, $item))->all(),
        ];
    }

    private function formatDocumentWithSubType(string $type, string $title, $collection, ?string $workOrderRelation = null): array
    {
        return [
            'id' => $type,
            'type' => $type,
            'title' => $title,
            'count' => $collection->count(),
            'items' => $collection->values()->map(function ($item) use ($type, $workOrderRelation) {
                $formatted = $this->formatDocumentItem($type, $item);

                // subType: process.process_name 기반
                $workOrder = $workOrderRelation ? $item->{$workOrderRelation} : $item;
                if ($workOrder instanceof WorkOrder) {
                    $processName = $workOrder->process?->process_name;
                    $formatted['sub_type'] = $this->mapProcessToSubType($processName);
                }

                return $formatted;
            })->all(),
        ];
    }

    private function formatDocumentItem(string $type, $item): array
    {
        return match ($type) {
            'import', 'report' => [
                'id' => (string) $item->id,
                'title' => $item->inspection_no ?? '',
                'date' => $item->inspection_date?->toDateString() ?? $item->request_date?->toDateString() ?? '',
                'code' => $item->inspection_no ?? '',
            ],
            'order' => [
                'id' => (string) $item->id,
                'title' => $item->order_no,
                'date' => $item->received_at?->toDateString() ?? '',
                'code' => $item->order_no,
            ],
            'log' => [
                'id' => (string) $item->id,
                'title' => $item->project_name ?? '작업일지',
                'date' => $item->created_at?->toDateString() ?? '',
                'code' => $item->id,
            ],
            'confirmation', 'shipping' => [
                'id' => (string) $item->id,
                'title' => $item->shipment_no ?? '',
                'date' => $item->scheduled_date?->toDateString() ?? '',
                'code' => $item->shipment_no ?? '',
            ],
            'product' => [
                'id' => (string) $item->id,
                'title' => '제품검사 성적서',
                'date' => $item->updated_at?->toDateString() ?? '',
                'code' => '',
            ],
            'quality' => [
                'id' => (string) $item->id,
                'title' => $item->quality_doc_number ?? '',
                'date' => $item->received_date?->toDateString() ?? '',
                'code' => $item->quality_doc_number ?? '',
            ],
            default => [
                'id' => (string) $item->id,
                'title' => '',
                'date' => '',
            ],
        };
    }

    /**
     * process_name → subType 매핑
     */
    private function mapProcessToSubType(?string $processName): ?string
    {
        if (! $processName) {
            return null;
        }

        $name = mb_strtolower($processName);

        return match (true) {
            str_contains($name, 'screen') || str_contains($name, '스크린') => 'screen',
            str_contains($name, 'bending') || str_contains($name, '절곡') => 'bending',
            str_contains($name, 'slat') || str_contains($name, '슬랫') => 'slat',
            str_contains($name, 'jointbar') || str_contains($name, '조인트바') || str_contains($name, 'joint') => 'jointbar',
            default => null,
        };
    }

    // ===== Private: Document Detail Methods (2단계 로딩) =====

    private function getInspectionDetail(int $id, string $type): array
    {
        $inspection = Inspection::where('inspection_type', $type)
            ->with(['item', 'workOrder.process'])
            ->findOrFail($id);

        return [
            'type' => $type === 'IQC' ? 'import' : 'report',
            'data' => [
                'id' => $inspection->id,
                'inspection_no' => $inspection->inspection_no,
                'inspection_type' => $inspection->inspection_type,
                'status' => $inspection->status,
                'result' => $inspection->result,
                'request_date' => $inspection->request_date?->toDateString(),
                'inspection_date' => $inspection->inspection_date?->toDateString(),
                'lot_no' => $inspection->lot_no,
                'item_name' => $inspection->item?->name,
                'process_name' => $inspection->workOrder?->process?->process_name,
                'meta' => $inspection->meta,
                'items' => $inspection->items,
                'attachments' => $inspection->attachments,
                'extra' => $inspection->extra,
            ],
        ];
    }

    private function getOrderDetail(int $id): array
    {
        $order = Order::with(['nodes' => fn ($q) => $q->whereNull('parent_id')])->findOrFail($id);

        return [
            'type' => 'order',
            'data' => [
                'id' => $order->id,
                'order_no' => $order->order_no,
                'status' => $order->status,
                'received_at' => $order->received_at?->toDateString(),
                'site_name' => $order->site_name,
                'nodes_count' => $order->nodes->count(),
            ],
        ];
    }

    private function getWorkOrderLogDetail(int $id): array
    {
        $workOrder = WorkOrder::with('process')->findOrFail($id);

        return [
            'type' => 'log',
            'data' => [
                'id' => $workOrder->id,
                'project_name' => $workOrder->project_name,
                'status' => $workOrder->status,
                'process_name' => $workOrder->process?->process_name,
                'options' => $workOrder->options,
                'created_at' => $workOrder->created_at?->toDateString(),
            ],
        ];
    }

    private function getShipmentDetail(int $id): array
    {
        $shipment = Shipment::findOrFail($id);

        return [
            'type' => 'shipping',
            'data' => [
                'id' => $shipment->id,
                'shipment_no' => $shipment->shipment_no,
                'status' => $shipment->status,
                'scheduled_date' => $shipment->scheduled_date?->toDateString(),
                'customer_name' => $shipment->customer_name,
                'site_name' => $shipment->site_name,
                'delivery_address' => $shipment->delivery_address,
                'delivery_method' => $shipment->delivery_method,
                'vehicle_no' => $shipment->vehicle_no,
                'driver_name' => $shipment->driver_name,
                'remarks' => $shipment->remarks,
            ],
        ];
    }

    private function getLocationDetail(int $id): array
    {
        $location = QualityDocumentLocation::with(['orderItem', 'document'])->findOrFail($id);

        return [
            'type' => 'product',
            'data' => [
                'id' => $location->id,
                'inspection_status' => $location->inspection_status,
                'inspection_data' => $location->inspection_data,
                'post_width' => $location->post_width,
                'post_height' => $location->post_height,
                'floor_code' => $location->orderItem?->floor_code,
                'symbol_code' => $location->orderItem?->symbol_code,
                'document_id' => $location->document_id,
            ],
        ];
    }

    private function getQualityDocDetail(int $id): array
    {
        $doc = QualityDocument::with(['client', 'inspector:id,name'])->findOrFail($id);

        return [
            'type' => 'quality',
            'data' => [
                'id' => $doc->id,
                'quality_doc_number' => $doc->quality_doc_number,
                'site_name' => $doc->site_name,
                'status' => $doc->status,
                'received_date' => $doc->received_date?->toDateString(),
                'client_name' => $doc->client?->name,
                'inspector_name' => $doc->inspector?->name,
                'options' => $doc->options,
            ],
        ];
    }
}
