<?php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/includes/db.php';
require_once dirname(__DIR__) . '/includes/functions.php';
require_once dirname(__DIR__) . '/includes/auth.php';
requirePermission('metadata_bulk_edit');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: metadata.php');
    exit;
}
requireCsrfToken();

$pdo = getDBConnection();
$action = (string)($_POST['action'] ?? '');

function redirectMetadata($message, $status = 'success') {
    $target = 'metadata.php';
    $referer = (string)($_SERVER['HTTP_REFERER'] ?? '');
    $path = parse_url($referer, PHP_URL_PATH);
    $file = $path ? basename((string)$path) : '';
    if (in_array($file, ['metadata.php', 'metadata_quality.php'], true)) {
        $target = $file;
    }
    header('Location: ' . $target . '?status=' . urlencode($status) . '&message=' . urlencode($message));
    exit;
}

function metadataSongSelectSql() {
    return "SELECT id, file_path, is_manual_edited, metadata_source FROM songs";
}

function metadataUpdateParams($metadata) {
    return [
        ':title' => $metadata['title'],
        ':artist' => $metadata['artist'],
        ':album' => $metadata['album'],
        ':album_artist' => $metadata['album_artist'],
        ':genre' => $metadata['genre'],
        ':year' => $metadata['year'],
        ':track_no' => $metadata['track_no'],
        ':disc_no' => $metadata['disc_no'],
        ':duration' => $metadata['duration'],
        ':composer' => $metadata['composer'],
        ':comment' => $metadata['comment'],
        ':bitrate' => $metadata['bitrate'],
        ':sample_rate' => $metadata['sample_rate'],
        ':channels' => $metadata['channels'],
        ':cover_hash' => $metadata['cover_hash'],
        ':cover_mime' => $metadata['cover_mime'],
        ':has_cover' => $metadata['has_cover'],
        ':metadata_source' => $metadata['metadata_source'],
        ':metadata_error' => $metadata['metadata_error'],
    ];
}

function reanalyzeSong($pdo, $song, $force = false, $mode = 'full') {
    if (empty($song['file_path'])) return false;
    $winPath = resolveFilesystemPath($song['file_path'], 'readable_file');
    if ($winPath === null) {
        $stmt = $pdo->prepare("
            UPDATE songs
            SET is_missing = 1,
                metadata_error = :metadata_error,
                last_metadata_scan_at = NOW(),
                metadata_updated_at = NOW()
            WHERE id = :id
        ");
        $stmt->execute([
            ':metadata_error' => 'File not found during metadata reanalysis',
            ':id' => $song['id'],
        ]);
        return false;
    }

    $metadata = extractMusicMetadata($song['file_path']);

    if ($mode === 'cover') {
        $stmt = $pdo->prepare("
            UPDATE songs
            SET cover_hash = :cover_hash,
                cover_mime = :cover_mime,
                has_cover = :has_cover,
                cover_cache_path = NULL,
                metadata_error = :metadata_error,
                last_metadata_scan_at = NOW(),
                metadata_updated_at = NOW(),
                is_missing = 0
            WHERE id = :id
        ");
        $stmt->execute([
            ':cover_hash' => $metadata['cover_hash'],
            ':cover_mime' => $metadata['cover_mime'],
            ':has_cover' => $metadata['has_cover'],
            ':metadata_error' => $metadata['metadata_error'],
            ':id' => $song['id'],
        ]);
        return true;
    }

    if ($mode === 'technical') {
        $stmt = $pdo->prepare("
            UPDATE songs
            SET duration = :duration,
                bitrate = :bitrate,
                sample_rate = :sample_rate,
                channels = :channels,
                metadata_error = :metadata_error,
                last_metadata_scan_at = NOW(),
                metadata_updated_at = NOW(),
                is_missing = 0
            WHERE id = :id
        ");
        $stmt->execute([
            ':duration' => $metadata['duration'],
            ':bitrate' => $metadata['bitrate'],
            ':sample_rate' => $metadata['sample_rate'],
            ':channels' => $metadata['channels'],
            ':metadata_error' => $metadata['metadata_error'],
            ':id' => $song['id'],
        ]);
        return true;
    }

    $manualProtected = !empty($song['is_manual_edited']) && !$force;
    if ($manualProtected) {
        $stmt = $pdo->prepare("
            UPDATE songs
            SET duration = :duration,
                bitrate = :bitrate,
                sample_rate = :sample_rate,
                channels = :channels,
                cover_hash = :cover_hash,
                cover_mime = :cover_mime,
                has_cover = :has_cover,
                cover_cache_path = NULL,
                metadata_source = CASE WHEN metadata_source IS NULL OR metadata_source = '' THEN :metadata_source ELSE metadata_source END,
                metadata_error = :metadata_error,
                last_metadata_scan_at = NOW(),
                metadata_updated_at = NOW(),
                is_missing = 0
            WHERE id = :id
        ");
        $stmt->execute([
            ':duration' => $metadata['duration'],
            ':bitrate' => $metadata['bitrate'],
            ':sample_rate' => $metadata['sample_rate'],
            ':channels' => $metadata['channels'],
            ':cover_hash' => $metadata['cover_hash'],
            ':cover_mime' => $metadata['cover_mime'],
            ':has_cover' => $metadata['has_cover'],
            ':metadata_source' => $metadata['metadata_source'],
            ':metadata_error' => $metadata['metadata_error'],
            ':id' => $song['id'],
        ]);
        return true;
    }

    $stmt = $pdo->prepare("
        UPDATE songs
        SET title = :title,
            artist = :artist,
            album = :album,
            album_artist = :album_artist,
            genre = :genre,
            year = :year,
            track_no = :track_no,
            disc_no = :disc_no,
            duration = :duration,
            composer = :composer,
            comment = :comment,
            bitrate = :bitrate,
            sample_rate = :sample_rate,
            channels = :channels,
            cover_hash = :cover_hash,
            cover_mime = :cover_mime,
            has_cover = :has_cover,
            cover_cache_path = NULL,
            metadata_source = :metadata_source,
            metadata_error = :metadata_error,
            last_metadata_scan_at = NOW(),
            metadata_updated_at = NOW(),
            is_manual_edited = CASE WHEN :force_manual = 1 THEN 0 ELSE is_manual_edited END,
            is_missing = 0
        WHERE id = :id
    ");
    $stmt->execute(array_merge(metadataUpdateParams($metadata), [
        ':force_manual' => $force ? 1 : 0,
        ':id' => $song['id'],
    ]));
    return true;
}

try {
    if ($action === 'manual_on' || $action === 'manual_off') {
        $songId = (int)($_POST['song_id'] ?? 0);
        $stmt = $pdo->prepare("
            UPDATE songs
            SET is_manual_edited = :flag,
                metadata_source = CASE WHEN :flag = 1 THEN 'manual' ELSE metadata_source END,
                metadata_updated_at = NOW()
            WHERE id = :id
        ");
        $flag = $action === 'manual_on' ? 1 : 0;
        $stmt->execute([':flag' => $flag, ':id' => $songId]);
        redirectMetadata($flag ? '수동 수정 보호를 설정했습니다.' : '수동 수정 보호를 해제했습니다.');
    }

    $mode = 'full';
    if ($action === 'reanalyze_cover') $mode = 'cover';
    if ($action === 'reanalyze_technical') $mode = 'technical';
    $force = in_array($action, ['reanalyze_force'], true);

    if ($action === 'reanalyze_one') {
        $songId = (int)($_POST['song_id'] ?? 0);
        $stmt = $pdo->prepare(metadataSongSelectSql() . " WHERE id = :id LIMIT 1");
        $stmt->execute([':id' => $songId]);
        $song = $stmt->fetch();
        if (!$song) redirectMetadata('곡을 찾을 수 없습니다.', 'error');
        reanalyzeSong($pdo, $song, false);
        redirectMetadata('선택한 곡을 파일 내부 메타데이터 기준으로 다시 읽었습니다.');
    }

    $songs = null;
    $where = 'is_missing = 0';
    if ($action === 'reanalyze_selected') {
        $ids = array_values(array_filter(array_map('intval', $_POST['song_ids'] ?? [])));
        if (empty($ids)) redirectMetadata('선택한 곡이 없습니다.', 'error');
        $placeholders = [];
        $params = [];
        foreach ($ids as $idx => $id) {
            $ph = ':id' . $idx;
            $placeholders[] = $ph;
            $params[$ph] = $id;
        }
        $stmt = $pdo->prepare(metadataSongSelectSql() . " WHERE id IN (" . implode(',', $placeholders) . ") ORDER BY id DESC LIMIT 100");
        $stmt->execute($params);
        $songs = $stmt->fetchAll();
    } elseif ($action === 'reanalyze_missing') {
        $where .= " AND (
            title IS NULL OR TRIM(title) = ''
            OR artist IS NULL OR TRIM(artist) = ''
            OR album IS NULL OR TRIM(album) = ''
            OR genre IS NULL OR TRIM(genre) = ''
            OR year IS NULL OR TRIM(year) = ''
            OR duration IS NULL OR duration <= 0
            OR COALESCE(has_cover, 0) = 0
        )";
    } elseif ($action === 'reanalyze_errors') {
        $where .= " AND metadata_error IS NOT NULL AND TRIM(metadata_error) != ''";
    } elseif ($action === 'reanalyze_non_manual') {
        $where .= ' AND COALESCE(is_manual_edited, 0) = 0';
    } elseif (!in_array($action, ['reanalyze_all', 'reanalyze_force', 'reanalyze_cover', 'reanalyze_technical'], true)) {
        redirectMetadata('지원하지 않는 작업입니다.', 'error');
    }

    if ($songs === null) {
        $songs = $pdo->query(metadataSongSelectSql() . " WHERE $where ORDER BY id DESC LIMIT 100")->fetchAll();
    }

    $success = 0;
    $failed = 0;
    $skipped = 0;
    foreach ($songs as $song) {
        try {
            if (reanalyzeSong($pdo, $song, $force, $mode)) $success++;
            else $skipped++;
        } catch (Throwable $e) {
            $failed++;
        }
    }
    logMaintenance('metadata_reanalyzed', "success=$success, failed=$failed, skipped=$skipped, force=" . ($force ? '1' : '0') . ", mode=$mode", $failed > 0 ? 'warning' : 'success');
    redirectMetadata("메타데이터 재분석 완료: 성공 {$success}곡, 실패 {$failed}곡, 건너뜀 {$skipped}곡");
} catch (Throwable $e) {
    logMaintenance('metadata_reanalyzed', $e->getMessage(), 'failed');
    redirectMetadata('메타데이터 작업 실패: ' . $e->getMessage(), 'error');
}
