import 'dart:convert';
import 'dart:developer' as developer;
import 'dart:io';

import 'package:asciineverdie/src/core/model/save_data.dart';
import 'package:asciineverdie/src/core/storage/save_integrity.dart';

/// Persists GameSave as JSON compressed with GZipCodec + HMAC-SHA256 integrity.
///
/// 파일 포맷: [32-byte HMAC][GZip data]
class SaveService {
  SaveService({required this.baseDir});

  final Directory baseDir;
  final GZipCodec _gzip = GZipCodec();

  Future<File> save(GameSave save, String fileName) async {
    final path = _resolvePath(fileName);
    final file = File(path);
    await file.parent.create(recursive: true);
    final jsonStr = jsonEncode(save.toJson());
    final bytes = utf8.encode(jsonStr);
    final compressed = _gzip.encode(bytes);
    // HMAC-SHA256 서명(signature) 추가
    final signed = SaveIntegrity.sign(compressed);
    return file.writeAsBytes(signed);
  }

  Future<GameSave> load(String fileName) async {
    final path = _resolvePath(fileName);
    final file = File(path);
    final fileBytes = await file.readAsBytes();

    // HMAC 무결성(integrity) 검증 — 구 포맷은 경고 후 통과
    final result = SaveIntegrity.verify(fileBytes);
    if (result.isLegacy) {
      developer.log(
        '레거시(legacy) 세이브 포맷 감지: $fileName — 다음 저장 시 HMAC 자동 추가',
        name: 'SaveService',
      );
    }

    final decompressed = _gzip.decode(result.gzipBytes);
    final jsonStr = utf8.decode(decompressed);
    final map = jsonDecode(jsonStr) as Map<String, dynamic>;
    return GameSave.fromJson(map);
  }

  String _resolvePath(String fileName) {
    final normalized = fileName.endsWith('.pqf') ? fileName : '$fileName.pqf';
    final file = File(normalized);
    if (file.isAbsolute) return file.path;
    return '${baseDir.path}/$normalized';
  }

  /// 저장 파일 삭제
  Future<void> deleteSave(String fileName) async {
    final path = _resolvePath(fileName);
    final file = File(path);
    if (await file.exists()) {
      await file.delete();
    }
  }

  /// 저장 파일 존재 여부 확인
  Future<bool> exists(String fileName) async {
    final path = _resolvePath(fileName);
    final file = File(path);
    return file.exists();
  }

  /// 저장 디렉토리의 모든 .pqf 파일 목록 반환
  Future<List<SaveFileInfo>> listSaves() async {
    if (!await baseDir.exists()) {
      return [];
    }

    final files = <SaveFileInfo>[];
    await for (final entity in baseDir.list()) {
      if (entity is File && entity.path.endsWith('.pqf')) {
        final stat = await entity.stat();
        final name = entity.uri.pathSegments.last;
        files.add(
          SaveFileInfo(
            fileName: name,
            fullPath: entity.path,
            modifiedAt: stat.modified,
            sizeBytes: stat.size,
          ),
        );
      }
    }

    // 최근 수정된 파일 순으로 정렬
    files.sort((a, b) => b.modifiedAt.compareTo(a.modifiedAt));
    return files;
  }
}

/// 저장 파일 정보
class SaveFileInfo {
  const SaveFileInfo({
    required this.fileName,
    required this.fullPath,
    required this.modifiedAt,
    required this.sizeBytes,
  });

  final String fileName;
  final String fullPath;
  final DateTime modifiedAt;
  final int sizeBytes;

  /// 확장자 없는 표시용 이름
  String get displayName => fileName.replaceAll('.pqf', '');
}
