import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';

import 'package:mini_tias/services/file_service.dart';
import 'package:mini_tias/services/permission_service.dart';
import 'package:mini_tias/services/raw_capture_service.dart';
import 'package:mini_tias/services/sound_service.dart';

/// カメラの初期化・プレビュー制御・撮影実行・ライフサイクルを管理する．
class CameraProvider extends ChangeNotifier {
  final PermissionService _permissionService = PermissionService();
  final FileService _fileService = FileService();
  final RawCaptureService _rawCaptureService = RawCaptureService();
  final SoundService _soundService = SoundService();

  CameraController? _controller;
  bool _isInitialized = false;
  String? _errorMessage;
  bool _permissionDenied = false;
  bool _permissionPermanentlyDenied = false;
  String? _lastSavedFileName;
  bool _isSaving = false;
  bool _imageStreamActive = false;
  Map<String, dynamic>? _latestFrame;

  CameraController? get controller => _controller;
  bool get isInitialized => _isInitialized;
  String? get errorMessage => _errorMessage;
  bool get permissionDenied => _permissionDenied;
  bool get permissionPermanentlyDenied => _permissionPermanentlyDenied;
  String? get lastSavedFileName => _lastSavedFileName;
  bool get isSaving => _isSaving;
  bool get isSoundEnabled => _soundService.isSoundEnabled;

  /// サウンド設定を切り替える．
  Future<void> toggleSound() async {
    await _soundService.toggleSound();
    notifyListeners();
  }

  /// シャッター音を再生する．
  Future<void> playShutterSound() async {
    await _soundService.playShutterSound();
  }

  /// カメラを初期化する．
  Future<void> initialize() async {
    await _soundService.init();

    final granted = await _permissionService.requestCamera();
    if (!granted) {
      _permissionDenied = true;
      _permissionPermanentlyDenied = await _permissionService
          .isCameraPermanentlyDenied();
      _errorMessage = 'カメラの権限が必要です';
      notifyListeners();
      return;
    }

    _permissionDenied = false;
    _permissionPermanentlyDenied = false;

    try {
      final cameras = await availableCameras();
      final frontCamera = cameras.firstWhere(
        (c) => c.lensDirection == CameraLensDirection.front,
      );

      _controller = CameraController(
        frontCamera,
        ResolutionPreset.max,
        enableAudio: false,
      );

      await _controller!.initialize();
      await _controller!.setFlashMode(FlashMode.off);
      _isInitialized = true;
      _errorMessage = null;

      _startImageStream();
    } catch (e) {
      _errorMessage = 'カメラの初期化に失敗しました: $e';
      _isInitialized = false;
    }

    notifyListeners();
  }

  /// 画像ストリームを開始して最新フレームを保持する．
  void _startImageStream() {
    if (_controller == null || _imageStreamActive) return;

    try {
      _controller!.startImageStream((CameraImage image) {
        _latestFrame = {
          'width': image.width,
          'height': image.height,
          'yPlane': Uint8List.fromList(image.planes[0].bytes),
          'uPlane': Uint8List.fromList(image.planes[1].bytes),
          'vPlane': Uint8List.fromList(image.planes[2].bytes),
          'yRowStride': image.planes[0].bytesPerRow,
          'uvRowStride': image.planes[1].bytesPerRow,
          'uvPixelStride': image.planes[1].bytesPerPixel ?? 1,
        };
      });
      _imageStreamActive = true;
    } catch (e) {
      debugPrint('画像ストリーム開始失敗: $e');
    }
  }

  /// 画像ストリームを停止する．
  Future<void> _stopImageStream() async {
    if (!_imageStreamActive || _controller == null) return;

    try {
      await _controller!.stopImageStream();
    } catch (_) {
      // 既に停止済みの場合等は無視
    }
    _imageStreamActive = false;
  }

  /// 最新のプレビューフレームを JPEG として取得する（オーバーレイなし）．
  Future<Uint8List?> capturePreviewSnapshot() async {
    if (_latestFrame == null) return null;

    final frame = _latestFrame!;
    return _rawCaptureService.convertYuvToJpeg(
      width: frame['width'] as int,
      height: frame['height'] as int,
      yPlane: frame['yPlane'] as Uint8List,
      uPlane: frame['uPlane'] as Uint8List,
      vPlane: frame['vPlane'] as Uint8List,
      yRowStride: frame['yRowStride'] as int,
      uvRowStride: frame['uvRowStride'] as int,
      uvPixelStride: frame['uvPixelStride'] as int,
      rotation: 90,
      mirror: true,
    );
  }

  /// Camera2 API でフル解像度 YUV キャプチャし，PNG で保存する．
  Future<void> takePicture() async {
    if (!_isInitialized || _isSaving) return;

    _isSaving = true;
    _isInitialized = false;
    notifyListeners();

    try {
      // ストレージ権限の確認
      final storageGranted = await _permissionService.requestStorage();
      if (!storageGranted) {
        _errorMessage = 'ストレージの権限が必要です';
        _isSaving = false;
        notifyListeners();
        return;
      }

      // 画像ストリームを停止してカメラを解放
      await _stopImageStream();
      await _controller?.dispose();
      _controller = null;

      // カメラが完全に解放されるまで待つ
      await Future.delayed(const Duration(milliseconds: 500));

      // 定量モード撮影（DNG 経路）
      // baseName を先に確定し，Kotlin 側で DNG を直接書き込む
      final baseName = await _fileService.generateQuantitativeBaseName();
      final capture = await _rawCaptureService.captureQuantitativeDng(
        baseName: baseName,
        directoryPath: _fileService.directoryPath,
      );
      debugPrint(
        'DNG saved: ${capture.dngFileSize} bytes at ${capture.dngPath}',
      );

      // メタデータ JSON は引き続き Dart 側で保存
      final metaPath = await _fileService.saveQuantitativeMetadata(
        baseName,
        capture.metadata,
        lscMap: capture.lscMap,
        lscMapRowCount: capture.lscMapRowCount,
        lscMapColumnCount: capture.lscMapColumnCount,
      );

      // MediaStore に登録（PC から MTP で見えるようにする）
      await _rawCaptureService.scanFile(capture.dngPath);
      await _rawCaptureService.scanFile(metaPath);

      _lastSavedFileName = capture.dngPath.split('/').last;
      _errorMessage = null;

      // 保存完了音を再生（エラーで撮影フロー全体は止めない）
      await _soundService.playSaveCompleteSound();
    } catch (e) {
      _errorMessage = '撮影に失敗しました: $e';
      _lastSavedFileName = null;
    }

    _isSaving = false;
    notifyListeners();

    // プレビューを再開
    await initialize();
  }

  /// カメラリソースを解放する．
  Future<void> disposeCamera() async {
    await _stopImageStream();
    _latestFrame = null;
    _controller?.dispose();
    _controller = null;
    _isInitialized = false;
    notifyListeners();
  }

  /// アプリの設定画面を開く（権限が永久拒否された場合）．
  Future<void> openSettings() async {
    await _permissionService.openSettings();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }
}
