<?php

namespace App\Services;

use App\Models\Qualitys\AuditChecklist;
use App\Models\Qualitys\AuditChecklistCategory;
use App\Models\Qualitys\AuditChecklistItem;
use App\Models\Qualitys\AuditStandardDocument;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class AuditChecklistService extends Service
{
    /**
     * 점검표 목록 (year, quarter 필터)
     */
    public function index(array $params): array
    {
        $query = AuditChecklist::with(['categories.items']);

        if (! empty($params['year'])) {
            $query->where('year', (int) $params['year']);
        }
        if (! empty($params['quarter'])) {
            $query->where('quarter', (int) $params['quarter']);
        }
        if (! empty($params['type'])) {
            $query->where('type', $params['type']);
        }

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

        $items = $paginated->getCollection()->map(fn ($checklist) => $this->transformListItem($checklist));

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

    /**
     * 점검표 생성 (카테고리+항목 일괄)
     */
    public function store(array $data): array
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 중복 체크
        $exists = AuditChecklist::where('year', $data['year'])
            ->where('quarter', $data['quarter'])
            ->where('type', $data['type'] ?? AuditChecklist::TYPE_STANDARD_MANUAL)
            ->exists();

        if ($exists) {
            throw new BadRequestHttpException(__('error.duplicate', ['attribute' => '해당 분기 점검표']));
        }

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            $checklist = AuditChecklist::create([
                'tenant_id' => $tenantId,
                'year' => $data['year'],
                'quarter' => $data['quarter'],
                'type' => $data['type'] ?? AuditChecklist::TYPE_STANDARD_MANUAL,
                'status' => AuditChecklist::STATUS_DRAFT,
                'created_by' => $userId,
                'updated_by' => $userId,
            ]);

            $this->syncCategories($checklist, $data['categories'], $tenantId);

            return $this->show($checklist->id);
        });
    }

    /**
     * 점검표 상세 (카테고리→항목→문서 중첩)
     */
    public function show(int $id): array
    {
        $checklist = AuditChecklist::with([
            'categories.items.standardDocuments.document',
        ])->findOrFail($id);

        return $this->transformDetail($checklist);
    }

    /**
     * 점검표 수정
     */
    public function update(int $id, array $data): array
    {
        $tenantId = $this->tenantId();

        $checklist = AuditChecklist::findOrFail($id);

        if ($checklist->isCompleted()) {
            throw new BadRequestHttpException('완료된 점검표는 수정할 수 없습니다.');
        }

        return DB::transaction(function () use ($checklist, $data, $tenantId) {
            $checklist->update([
                'updated_by' => $this->apiUserId(),
            ]);

            if (isset($data['categories'])) {
                $this->syncCategories($checklist, $data['categories'], $tenantId);
            }

            return $this->show($checklist->id);
        });
    }

    /**
     * 점검표 완료 처리
     */
    public function complete(int $id): array
    {
        $checklist = AuditChecklist::with('categories.items')->findOrFail($id);

        // 미완료 항목 확인
        $totalItems = 0;
        $completedItems = 0;
        foreach ($checklist->categories as $category) {
            foreach ($category->items as $item) {
                $totalItems++;
                if ($item->is_completed) {
                    $completedItems++;
                }
            }
        }

        if ($completedItems < $totalItems) {
            throw new BadRequestHttpException("미완료 항목이 있습니다. ({$completedItems}/{$totalItems})");
        }

        $checklist->update([
            'status' => AuditChecklist::STATUS_COMPLETED,
            'updated_by' => $this->apiUserId(),
        ]);

        return $this->show($checklist->id);
    }

    /**
     * 항목 완료/미완료 토글
     */
    public function toggleItem(int $itemId): array
    {
        $item = AuditChecklistItem::findOrFail($itemId);
        $userId = $this->apiUserId();

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

            $newCompleted = ! $item->is_completed;
            $item->update([
                'is_completed' => $newCompleted,
                'completed_at' => $newCompleted ? now() : null,
                'completed_by' => $newCompleted ? $userId : null,
            ]);

            // 점검표 상태 자동 업데이트: draft → in_progress
            $category = $item->category;
            $checklist = $category->checklist;
            if ($checklist->isDraft()) {
                $checklist->update([
                    'status' => AuditChecklist::STATUS_IN_PROGRESS,
                    'updated_by' => $userId,
                ]);
            }
        });

        $item->refresh();

        return [
            'id' => (string) $item->id,
            'name' => $item->name,
            'is_completed' => $item->is_completed,
            'completed_at' => $item->completed_at?->toIso8601String(),
        ];
    }

    /**
     * 항목별 기준 문서 조회
     */
    public function itemDocuments(int $itemId): array
    {
        $item = AuditChecklistItem::findOrFail($itemId);

        return $item->standardDocuments()->with('document')->get()
            ->map(fn ($doc) => $this->transformStandardDocument($doc))
            ->all();
    }

    /**
     * 기준 문서 연결
     */
    public function attachDocument(int $itemId, array $data): array
    {
        $item = AuditChecklistItem::findOrFail($itemId);
        $tenantId = $this->tenantId();

        $doc = AuditStandardDocument::create([
            'tenant_id' => $tenantId,
            'checklist_item_id' => $item->id,
            'title' => $data['title'],
            'version' => $data['version'] ?? null,
            'date' => $data['date'] ?? null,
            'document_id' => $data['document_id'] ?? null,
        ]);

        $doc->load('document');

        return $this->transformStandardDocument($doc);
    }

    /**
     * 기준 문서 연결 해제
     */
    public function detachDocument(int $itemId, int $docId): void
    {
        $doc = AuditStandardDocument::where('checklist_item_id', $itemId)
            ->where('id', $docId)
            ->firstOrFail();

        $doc->delete();
    }

    // ===== Private: Sync & Transform =====

    private function syncCategories(AuditChecklist $checklist, array $categoriesData, int $tenantId): void
    {
        // 기존 카테고리 ID 추적 (삭제 감지용)
        $existingCategoryIds = $checklist->categories()->pluck('id')->all();
        $keptCategoryIds = [];

        foreach ($categoriesData as $catIdx => $catData) {
            if (! empty($catData['id'])) {
                // 기존 카테고리 업데이트
                $category = AuditChecklistCategory::findOrFail($catData['id']);
                $category->update([
                    'title' => $catData['title'],
                    'sort_order' => $catData['sort_order'] ?? $catIdx,
                ]);
                $keptCategoryIds[] = $category->id;
            } else {
                // 새 카테고리 생성
                $category = AuditChecklistCategory::create([
                    'tenant_id' => $tenantId,
                    'checklist_id' => $checklist->id,
                    'title' => $catData['title'],
                    'sort_order' => $catData['sort_order'] ?? $catIdx,
                ]);
                $keptCategoryIds[] = $category->id;
            }

            // 하위 항목 동기화
            $this->syncItems($category, $catData['items'] ?? [], $tenantId);
        }

        // 삭제된 카테고리 제거 (cascade로 items도 삭제)
        $deletedIds = array_diff($existingCategoryIds, $keptCategoryIds);
        if (! empty($deletedIds)) {
            AuditChecklistCategory::whereIn('id', $deletedIds)->delete();
        }
    }

    private function syncItems(AuditChecklistCategory $category, array $itemsData, int $tenantId): void
    {
        $existingItemIds = $category->items()->pluck('id')->all();
        $keptItemIds = [];

        foreach ($itemsData as $itemIdx => $itemData) {
            if (! empty($itemData['id'])) {
                $item = AuditChecklistItem::findOrFail($itemData['id']);
                $item->update([
                    'name' => $itemData['name'],
                    'description' => $itemData['description'] ?? null,
                    'sort_order' => $itemData['sort_order'] ?? $itemIdx,
                ]);
                $keptItemIds[] = $item->id;
            } else {
                $item = AuditChecklistItem::create([
                    'tenant_id' => $tenantId,
                    'category_id' => $category->id,
                    'name' => $itemData['name'],
                    'description' => $itemData['description'] ?? null,
                    'sort_order' => $itemData['sort_order'] ?? $itemIdx,
                ]);
                $keptItemIds[] = $item->id;
            }
        }

        $deletedIds = array_diff($existingItemIds, $keptItemIds);
        if (! empty($deletedIds)) {
            AuditChecklistItem::whereIn('id', $deletedIds)->delete();
        }
    }

    private function transformListItem(AuditChecklist $checklist): array
    {
        $total = 0;
        $completed = 0;
        foreach ($checklist->categories as $category) {
            foreach ($category->items as $item) {
                $total++;
                if ($item->is_completed) {
                    $completed++;
                }
            }
        }

        return [
            'id' => (string) $checklist->id,
            'year' => $checklist->year,
            'quarter' => $checklist->quarter,
            'type' => $checklist->type,
            'status' => $checklist->status,
            'progress' => [
                'completed' => $completed,
                'total' => $total,
            ],
        ];
    }

    private function transformDetail(AuditChecklist $checklist): array
    {
        $total = 0;
        $completed = 0;

        $categories = $checklist->categories->map(function ($category) use (&$total, &$completed) {
            $subItems = $category->items->map(function ($item) use (&$total, &$completed) {
                $total++;
                if ($item->is_completed) {
                    $completed++;
                }

                return [
                    'id' => (string) $item->id,
                    'name' => $item->name,
                    'description' => $item->description,
                    'is_completed' => $item->is_completed,
                    'completed_at' => $item->completed_at?->toIso8601String(),
                    'sort_order' => $item->sort_order,
                    'standard_documents' => $item->standardDocuments->map(
                        fn ($doc) => $this->transformStandardDocument($doc)
                    )->all(),
                ];
            })->all();

            return [
                'id' => (string) $category->id,
                'title' => $category->title,
                'sort_order' => $category->sort_order,
                'sub_items' => $subItems,
            ];
        })->all();

        return [
            'id' => (string) $checklist->id,
            'year' => $checklist->year,
            'quarter' => $checklist->quarter,
            'type' => $checklist->type,
            'status' => $checklist->status,
            'progress' => [
                'completed' => $completed,
                'total' => $total,
            ],
            'categories' => $categories,
        ];
    }

    private function transformStandardDocument(AuditStandardDocument $doc): array
    {
        $file = $doc->document;

        return [
            'id' => (string) $doc->id,
            'title' => $doc->title,
            'version' => $doc->version ?? '-',
            'date' => $doc->date?->toDateString() ?? '',
            'file_name' => $file?->original_name ?? null,
            'file_url' => $file ? "/api/v1/documents/{$file->id}/download" : null,
        ];
    }
}
