<?php

namespace App\Services;

use App\Models\Equipment\Equipment;
use Illuminate\Support\Facades\Log;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;

class EquipmentImportService
{
    public function __construct(
        private readonly EquipmentPhotoService $photoService
    ) {}

    private const HEADER_MAP = [
        '설비코드' => 'equipment_code',
        '설비명' => 'name',
        '설비유형' => 'equipment_type',
        '규격' => 'specification',
        '제조사' => 'manufacturer',
        '모델명' => 'model_name',
        '제조번호' => 'serial_no',
        '위치' => 'location',
        '생산라인' => 'production_line',
        '구입일' => 'purchase_date',
        '설치일' => 'install_date',
        '구입가격' => 'purchase_price',
        '내용연수' => 'useful_life',
        '상태' => 'status',
        '담당자' => 'manager_name',
        '비고' => 'memo',
        // 영문 매핑 (호환)
        'equipment_code' => 'equipment_code',
        'name' => 'name',
        'equipment_type' => 'equipment_type',
        'specification' => 'specification',
        'manufacturer' => 'manufacturer',
        'model_name' => 'model_name',
        'serial_no' => 'serial_no',
        'location' => 'location',
        'production_line' => 'production_line',
        'purchase_date' => 'purchase_date',
        'install_date' => 'install_date',
        'purchase_price' => 'purchase_price',
        'useful_life' => 'useful_life',
        'status' => 'status',
        'manager_name' => 'manager_name',
        'memo' => 'memo',
    ];

    private const STATUS_MAP = [
        '가동' => 'active',
        '사용' => 'active',
        '정상' => 'active',
        '유휴' => 'idle',
        '대기' => 'idle',
        '폐기' => 'disposed',
        '처분' => 'disposed',
        'active' => 'active',
        'idle' => 'idle',
        'disposed' => 'disposed',
    ];

    /**
     * 엑셀 파일 미리보기 (헤더 + 첫 10행)
     */
    public function preview(string $filePath): array
    {
        $spreadsheet = IOFactory::load($filePath);
        $sheet = $spreadsheet->getActiveSheet();
        $rows = $sheet->toArray(null, true, true, true);

        if (empty($rows)) {
            throw new \RuntimeException('빈 파일입니다.');
        }

        // 첫 행 = 헤더
        $headerRow = array_shift($rows);
        $headers = $this->mapHeaders($headerRow);

        if (empty($headers)) {
            throw new \RuntimeException('인식 가능한 헤더가 없습니다. 설비코드, 설비명 등의 헤더가 필요합니다.');
        }

        // 미리보기 10행
        $previewRows = [];
        $count = 0;
        foreach ($rows as $row) {
            if ($count >= 10) {
                break;
            }
            $mapped = $this->mapRow($row, $headers);
            if ($mapped) {
                $previewRows[] = $mapped;
                $count++;
            }
        }

        return [
            'headers' => array_values($headers),
            'original_headers' => array_values(array_filter($headerRow)),
            'preview' => $previewRows,
            'total_rows' => count($rows),
            'mapped_columns' => count($headers),
        ];
    }

    /**
     * 엑셀 데이터 일괄 등록
     */
    public function import(string $filePath, array $options = []): array
    {
        $duplicateAction = $options['duplicate_action'] ?? 'skip';
        $tenantId = session('selected_tenant_id', 1);

        $spreadsheet = IOFactory::load($filePath);
        $sheet = $spreadsheet->getActiveSheet();

        // Drawing을 행 번호별로 그룹핑 (toArray 호출 전에 추출)
        $drawingsByRow = $this->extractDrawingsByRow($sheet);

        $rows = $sheet->toArray(null, true, true, true);

        if (empty($rows)) {
            $spreadsheet->disconnectWorksheets();
            unset($spreadsheet);
            throw new \RuntimeException('빈 파일입니다.');
        }

        // 첫 행(헤더) 제거 — 키는 2,3,4... 유지되어 Drawing 행 번호와 매칭
        $headerRow = array_shift($rows);
        $headers = $this->mapHeaders($headerRow);

        $result = [
            'success' => 0,
            'failed' => 0,
            'skipped' => 0,
            'photos_uploaded' => 0,
            'photos_skipped' => 0,
            'errors' => [],
        ];

        foreach ($rows as $rowNum => $row) {
            $mapped = $this->mapRow($row, $headers);

            if (! $mapped || empty($mapped['equipment_code'])) {
                continue;
            }

            try {
                $existing = Equipment::where('tenant_id', $tenantId)
                    ->where('equipment_code', $mapped['equipment_code'])
                    ->first();

                if ($existing) {
                    if ($duplicateAction === 'overwrite') {
                        $this->updateEquipment($existing, $mapped);
                        $result['success']++;

                        // 기존 사진이 없을 때만 사진 업로드
                        if ($existing->photos()->count() === 0 && isset($drawingsByRow[$rowNum])) {
                            $result = $this->processDrawingsForEquipment($existing, $drawingsByRow[$rowNum], $result);
                        } elseif (isset($drawingsByRow[$rowNum])) {
                            $result['photos_skipped'] += count($drawingsByRow[$rowNum]);
                        }
                    } else {
                        $result['skipped']++;
                    }

                    continue;
                }

                $equipment = $this->createEquipment($mapped, $tenantId);
                $result['success']++;

                // 새 설비에 사진 업로드
                if (isset($drawingsByRow[$rowNum])) {
                    $result = $this->processDrawingsForEquipment($equipment, $drawingsByRow[$rowNum], $result);
                }
            } catch (\Exception $e) {
                $result['failed']++;
                $result['errors'][] = "행 {$rowNum}: {$e->getMessage()}";
                Log::warning('EquipmentImport: 행 처리 실패', [
                    'row' => $rowNum,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        $spreadsheet->disconnectWorksheets();
        unset($spreadsheet);

        return $result;
    }

    /**
     * Drawing을 행 번호별로 그룹핑
     *
     * @return array<int, BaseDrawing[]>
     */
    private function extractDrawingsByRow(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet): array
    {
        $drawingsByRow = [];

        foreach ($sheet->getDrawingCollection() as $drawing) {
            $coordinate = $drawing->getCoordinates();
            // "F2" → row 2
            $row = (int) preg_replace('/[A-Z]+/', '', $coordinate);

            if ($row <= 1) {
                continue; // 헤더 행 건너뜀
            }

            $drawingsByRow[$row][] = $drawing;
        }

        return $drawingsByRow;
    }

    /**
     * Drawing을 임시 파일로 저장
     *
     * @return array{0: string, 1: string, 2: string}|null [tempPath, extension, originalName]
     */
    private function saveDrawingToTempFile(BaseDrawing $drawing): ?array
    {
        try {
            if ($drawing instanceof MemoryDrawing) {
                $resource = $drawing->getImageResource();
                if (! $resource) {
                    return null;
                }

                $extension = match ($drawing->getMimeType()) {
                    MemoryDrawing::MIMETYPE_PNG => 'png',
                    MemoryDrawing::MIMETYPE_GIF => 'gif',
                    default => 'jpg',
                };

                $tempPath = tempnam(sys_get_temp_dir(), 'eq_import_');
                if ($extension === 'png') {
                    imagepng($resource, $tempPath);
                } elseif ($extension === 'gif') {
                    imagegif($resource, $tempPath);
                } else {
                    imagejpeg($resource, $tempPath, 90);
                }

                $originalName = $drawing->getName() ?: 'equipment_photo.'.$extension;

                return [$tempPath, $extension, $originalName];
            }

            if ($drawing instanceof Drawing) {
                $sourcePath = $drawing->getPath();
                if (! file_exists($sourcePath)) {
                    return null;
                }

                $extension = strtolower(pathinfo($sourcePath, PATHINFO_EXTENSION)) ?: 'jpg';
                $tempPath = tempnam(sys_get_temp_dir(), 'eq_import_');
                copy($sourcePath, $tempPath);

                $originalName = $drawing->getName() ?: basename($sourcePath);

                return [$tempPath, $extension, $originalName];
            }
        } catch (\Throwable $e) {
            Log::warning('EquipmentImport: Drawing 임시파일 저장 실패', [
                'error' => $e->getMessage(),
            ]);
        }

        return null;
    }

    /**
     * Drawing 목록을 설비에 사진으로 업로드
     */
    private function processDrawingsForEquipment(Equipment $equipment, array $drawings, array $result): array
    {
        foreach ($drawings as $drawing) {
            $saved = $this->saveDrawingToTempFile($drawing);
            if (! $saved) {
                $result['photos_skipped']++;

                continue;
            }

            [$tempPath, $extension, $originalName] = $saved;

            try {
                $uploaded = $this->photoService->uploadPhotoFromPath(
                    $equipment,
                    $tempPath,
                    $originalName,
                    $extension
                );

                if ($uploaded) {
                    $result['photos_uploaded']++;
                } else {
                    $result['photos_skipped']++;
                }
            } catch (\Throwable $e) {
                $result['photos_skipped']++;
                Log::warning('EquipmentImport: 사진 업로드 실패', [
                    'equipment_id' => $equipment->id,
                    'error' => $e->getMessage(),
                ]);
            } finally {
                if (file_exists($tempPath)) {
                    @unlink($tempPath);
                }
            }
        }

        return $result;
    }

    private function mapHeaders(array $headerRow): array
    {
        $mapped = [];
        foreach ($headerRow as $col => $value) {
            $value = trim((string) $value);
            if (isset(self::HEADER_MAP[$value])) {
                $mapped[$col] = self::HEADER_MAP[$value];
            }
        }

        return $mapped;
    }

    private function mapRow(array $row, array $headers): ?array
    {
        $mapped = [];
        $hasData = false;

        foreach ($headers as $col => $field) {
            $value = isset($row[$col]) ? trim((string) $row[$col]) : '';

            if ($field === 'status') {
                $value = self::STATUS_MAP[mb_strtolower($value)] ?? 'active';
            }

            if ($field === 'purchase_date' || $field === 'install_date') {
                $value = $this->parseDate($value);
            }

            if ($field === 'purchase_price') {
                $value = $value !== '' ? (float) preg_replace('/[^0-9.]/', '', $value) : null;
            }

            if ($field === 'useful_life') {
                $value = $value !== '' ? (int) preg_replace('/[^0-9]/', '', $value) : null;
            }

            if ($value !== '' && $value !== null) {
                $hasData = true;
            }

            $mapped[$field] = $value;
        }

        return $hasData ? $mapped : null;
    }

    private function parseDate(string $value): ?string
    {
        if (empty($value)) {
            return null;
        }

        // 엑셀 날짜 시리얼 번호
        if (is_numeric($value)) {
            try {
                $date = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject((int) $value);

                return $date->format('Y-m-d');
            } catch (\Exception) {
                return null;
            }
        }

        // 일반 날짜 문자열
        foreach (['Y-m-d', 'Y/m/d', 'Y.m.d', 'Ymd'] as $format) {
            $date = \DateTime::createFromFormat($format, $value);
            if ($date) {
                return $date->format('Y-m-d');
            }
        }

        return null;
    }

    private function createEquipment(array $data, int $tenantId): Equipment
    {
        $managerName = $data['manager_name'] ?? null;
        unset($data['manager_name']);

        $data['tenant_id'] = $tenantId;
        $data['created_by'] = auth()->id();

        if (! isset($data['status'])) {
            $data['status'] = 'active';
        }

        if ($managerName) {
            $user = \App\Models\User::where('name', $managerName)->first();
            if ($user) {
                $data['manager_id'] = $user->id;
            }
        }

        return Equipment::create($data);
    }

    private function updateEquipment(Equipment $equipment, array $data): void
    {
        $managerName = $data['manager_name'] ?? null;
        unset($data['manager_name']);

        $data['updated_by'] = auth()->id();

        if ($managerName) {
            $user = \App\Models\User::where('name', $managerName)->first();
            if ($user) {
                $data['manager_id'] = $user->id;
            }
        }

        $equipment->update($data);
    }
}
