<?php

namespace App\Jobs;

use App\Models\Song;
use App\Models\Artist;
use App\Models\SongCategory;
use App\Enums\ArtistCategory;
use App\Enums\SongLanguageType;
use App\Enums\SongSituation;
use App\Helpers\ChineseNameConverter;
use App\Helpers\ChineseStrokesConverter;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;

class ImportSongChunkJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected Collection $rows;
    protected String $id;
    protected array $categoryMap = [];
    protected array $artistCache =[];

    public function __construct(Collection $rows,String $id)
    {
        $this->rows = $rows;
        $this->id = $id;
        $this->categoryMap = SongCategory::pluck('id', 'code')->toArray();
    }

    public function handle(): void
    {
        Log::warning('匯入啟動', [
            'model' => "ImportSongChunkJob",
            'rows_id' =>$this->id,
        ]);
        $ToInsert = [];
        $artistMap = [];
        $categoryMap = [];
        $pMap = [
            '\\\\SVR01\\DISK01\\' => 'DISK01\\',
            '\\\\SVR01\\DISK02\\' => 'DISK02\\',
            '\\\\SVR01\\DISK03\\' => 'DISK03\\',
            '\\\\SVR01\\DISK04\\' => 'DISK04\\',
            '\\\\SVR01\\DISK05\\' => 'DISK05\\',
            '\\\\SVR01\\DISK06\\' => 'DISK06\\',
            '\\\\SVR01\\DISK07\\' => 'DISK07\\',
            '\\\\SVR01\\DISK08\\' => 'DISK08\\',
            '\\\\SVR01\\DISK09\\' => 'DISK09\\',
        ];
        foreach ($this->rows as $index => $row) {
            $songId = trim($row['編號'] ?? '');

            if (!$songId || Song::where('id', $songId)->exists()) {
                continue;
            }

            try {
                // 字元處理
                $songName=$this->normalizeName($row['歌名'] ?? '');
                $simplified=ChineseNameConverter::convertToSimplified($songName);// 繁體轉簡體
                if (!$row->has('注音')) {
                    $phoneticAbbr = ChineseNameConverter::getKTVZhuyinAbbr($simplified);// 注音符號
                } else {
                    $phoneticAbbr = trim($row['注音'] ?? '');
                }
                if (!$row->has('拼音')) {
                    $pinyinAbbr = ChineseNameConverter::getKTVPinyinAbbr($simplified);// 拼音首字母
                } else {
                    $pinyinAbbr = trim($row['拼音'] ?? '');
                }
                if (!$row->has('kk3')) {//歌名第一個字筆畫
                    $chars = preg_split('//u', $songName, -1, PREG_SPLIT_NO_EMPTY);
                    $firstChar = $chars[0] ?? null;
                    $strokesAbbr=( $firstChar && preg_match('/\p{Han}/u', $firstChar) )? ChineseStrokesConverter::getStrokes($firstChar) : 0;
                } else {
                    $strokesAbbr=trim($row['kk3'] ?? 0);
                } 
                if (!$row->has('kk4')) {//歌名字數
                    $songNumber = mb_strlen($songName, 'UTF-8');
                } else {
                    $songNumber=trim($row['kk4'] ?? 0);
                }
                $pathKey = trim($row['路徑01'] ?? '');
                $disk = $pMap[$pathKey] ?? '';
                $filename = trim($row['檔名'] ?? '');
                // 準備 song 資料
                $ToInsert[] = [
                    'id' => $songId,
                    'name' => $this->formatText($row['歌名']),
                    'adddate' => $this->parseExcelDate($row['日期'] ?? null),
                    'filename' => $disk . $filename,
                    //'language_type' => SongLanguageType::tryFrom(trim($row['語別'] ?? '')) ?? SongLanguageType::Unset,
                    'language_type' => SongLanguageType::fromLabelOrName($row['語別'] ?? ''),
                    'db_change' => trim($row['kk2'] ?? 0),//分貝增減
                    'vocal' => trim($row['kk6'] ?? 0),//人聲
                    'situation' => SongSituation::tryFrom(trim($row['kk7'] ?? '')) ?? SongSituation::Unset,//情境
                    'copyright01' => trim($row['版權01'] ?? ''),
                    'copyright02' => trim($row['版權02'] ?? ''),
                    'note01' => trim($row['版權03'] ?? ''),
                    'note02' => trim($row['版權04'] ?? ''),
                    'note03' => trim($row['版權05'] ?? ''),
                    'note04' => trim($row['版權06'] ?? ''),
                    'enable' => trim($row['狀態'] ?? 1),
                    'simplified' => $simplified,
                    'phonetic_abbr' => $phoneticAbbr,
                    'pinyin_abbr' => $pinyinAbbr,
                    'strokes_abbr' => $strokesAbbr,
                    'song_number' => $songNumber,
                    'song_counts' => trim($row['點播次數'] ?? 0),
                ];

                // 處理關聯 - 歌手
                $artistIds = [];
                foreach (['歌星A', '歌星B'] as $key) {
                    $artistName = $this->normalizeName($row[$key] ?? '');
                    if ($artistName === '') continue;
                
                    // 若是歌星B，且與歌星A相同，則跳過
                    if ($key === '歌星B' && $artistName === $this->normalizeName($row['歌星A'] ?? '')) continue;
                
                    $artistMap[$songId][] = $this->getOrCreateArtistId($artistName);
                }

                // 分類處理（多個用 , 分隔）
                if (!empty($row['分類'])) {
                    $categoryIds = [];
                    $codes = explode(',', $row['分類']);
                    foreach ($codes as $code) {
                        $code = trim($code);
                        if (isset($this->categoryMap[$code])) {
                            $categoryMap[$songId][] = $this->categoryMap[$code];
                        }
                    }
                }
            } catch (\Throwable $e) {
                \Log::error("Row {$index} failed: {$e->getMessage()}", [
                    'row' => $row,
                    'trace' => $e->getTraceAsString()
                ]);
            }
        }
        // 寫入資料庫
        Song::insert($ToInsert);
        // 同步關聯（建議可用事件或批次處理）
        foreach ($artistMap as $songId => $artistIds) {
            $song = Song::find($songId);
            if ($song) {
                $song->artists()->sync($artistIds);
            }
        }
        foreach ($categoryMap as $songId => $categoryIds) {
            $song = Song::find($songId);
            if ($song) {
                $song->categories()->sync($categoryIds);
            }
        }
    }
    private function getOrCreateArtistId(string $name): int
    {
        if (isset($this->artistCache[$name])) {
            return $this->artistCache[$name];
        }

        $artist = Artist::firstOrCreate(
            ['name' => $name],
            ['category' => ArtistCategory::Unset]
        );

        return $this->artistCache[$name] = $artist->id;
    }

    public function normalizeName(?string $str): string
    {
        return strtoupper(mb_convert_kana(trim($str ?? ''), 'as'));
    }

    protected function formatText($value)
    {
        if (is_numeric($value) && $value < 1 && $value > 0) {
            // 嘗試判斷為時間類型的小數，轉為時間字串
            $time = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
            return $time->format('H:i');
        }

        return trim((string) $value);
    }
    private function parseExcelDate($value): ?string
    {
        if (is_numeric($value)) {
            return \Carbon\Carbon::createFromFormat('Y-m-d', '1900-01-01')
                ->addDays((int)$value - 2)
                ->format('Y-m-d');
        }

        try {
            return \Carbon\Carbon::parse($value)->format('Y-m-d');
        } catch (\Exception $e) {
            return null;
        }
    }
}