import 'dart:async';

import 'package:ar_flutter_plugin_updated/ar_flutter_plugin.dart';
import 'package:ar_flutter_plugin_updated/datatypes/config_planedetection.dart';
import 'package:ar_flutter_plugin_updated/datatypes/node_types.dart';
import 'package:ar_flutter_plugin_updated/managers/ar_anchor_manager.dart';
import 'package:ar_flutter_plugin_updated/managers/ar_location_manager.dart';
import 'package:ar_flutter_plugin_updated/managers/ar_object_manager.dart';
import 'package:ar_flutter_plugin_updated/managers/ar_session_manager.dart';
import 'package:ar_flutter_plugin_updated/models/ar_node.dart';
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

import '../services/ar_model_asset_service.dart';

class ARPage extends StatefulWidget {
  const ARPage({
    super.key,
    required this.namaWisata,
    required this.modelPath,
  });

  final String namaWisata;
  final String modelPath;

  @override
  State<ARPage> createState() => _ARPageState();
}

class _ARPageState extends State<ARPage> {
  final ArModelAssetService _modelAssetService = const ArModelAssetService();
  ARSessionManager? _arSessionManager;
  ARObjectManager? _arObjectManager;
  ARNode? _modelNode;

  bool _sedangMemuat = true;
  bool _sedangMenambahkanModel = false;
  bool _modelSudahTampil = false;
  String? _pesanError;

  double _skalaModel = 0.28;
  double _rotasiY = 0;
  vector.Vector3 _posisiModel = vector.Vector3(0, -0.18, -1.25);

  double _skalaAwalGestur = 0.28;
  double _rotasiAwalGestur = 0;
  Offset? _titikGeserTerakhir;

  @override
  void dispose() {
    final node = _modelNode;
    final objectManager = _arObjectManager;
    if (node != null && objectManager != null) {
      unawaited(objectManager.removeNode(node));
    }
    _arSessionManager?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        children: [
          ARView(
            onARViewCreated: _onARViewCreated,
            planeDetectionConfig: PlaneDetectionConfig.horizontal,
            permissionPromptDescription:
                'Izin kamera diperlukan untuk menampilkan wisata dalam AR.',
            permissionPromptButtonText: 'Izinkan Kamera',
          ),
          Positioned.fill(
            child: GestureDetector(
              behavior: HitTestBehavior.translucent,
              onScaleStart: _mulaiGestur,
              onScaleUpdate: _ubahGestur,
            ),
          ),
          _barAtas(),
          if (_sedangMemuat) _indikatorMemuat(),
          if (_pesanError != null) _panelError(),
        ],
      ),
    );
  }

  void _onARViewCreated(
    ARSessionManager sessionManager,
    ARObjectManager objectManager,
    ARAnchorManager anchorManager,
    ARLocationManager locationManager,
  ) {
    _arSessionManager = sessionManager;
    _arObjectManager = objectManager;

    _arSessionManager!.onInitialize(
      showAnimatedGuide: false,
      showFeaturePoints: false,
      showPlanes: false,
      showWorldOrigin: false,
      handleTaps: false,
      handlePans: false,
      handleRotation: false,
    );
    _arObjectManager!.onInitialize();
    _arSessionManager!.onError = _handleArError;

    unawaited(_tampilkanModelDiDepanKamera());
  }

  Future<void> _tampilkanModelDiDepanKamera() async {
    if (_sedangMenambahkanModel) return;
    _sedangMenambahkanModel = true;

    await Future<void>.delayed(const Duration(milliseconds: 1500));
    if (!mounted || _modelSudahTampil || _arObjectManager == null) {
      _sedangMenambahkanModel = false;
      return;
    }

    try {
      final localModelPath =
          await _modelAssetService.prepareGlbForAr(widget.modelPath);
      if (!mounted) return;

      final node = ARNode(
        type: NodeType.fileSystemAppFolderGLB,
        uri: localModelPath,
        position: _posisiModel,
        scale: vector.Vector3.all(_skalaModel),
        eulerAngles: vector.Vector3(0, _rotasiY, 0),
      );

      final berhasil = await _arObjectManager!.addNode(node) ?? false;
      if (!mounted) return;

      if (berhasil) {
        setState(() {
          _modelNode = node;
          _modelSudahTampil = true;
          _sedangMemuat = false;
        });
      } else {
        setState(() {
          _sedangMemuat = false;
          _pesanError =
              'Model 3D belum bisa dimuat. Pastikan jalur aset sudah benar: ${widget.modelPath}';
        });
      }
    } on ArModelAssetException catch (exception) {
      if (!mounted) return;
      setState(() {
        _sedangMemuat = false;
        _pesanError = exception.message;
      });
    } catch (error) {
      debugPrint('[AR Model] Gagal memuat ${widget.modelPath}: $error');
      if (!mounted) return;
      setState(() {
        _sedangMemuat = false;
        _pesanError =
            'Model 3D belum bisa dimuat. Pastikan jalur aset sudah benar: ${widget.modelPath}';
      });
    } finally {
      _sedangMenambahkanModel = false;
    }
  }

  void _handleArError(String error) {
    debugPrint('[AR Model] Native AR error: $error');
    if (!mounted) return;
    setState(() {
      _sedangMemuat = false;
      _pesanError = error;
    });
  }

  void _mulaiGestur(ScaleStartDetails detail) {
    _skalaAwalGestur = _skalaModel;
    _rotasiAwalGestur = _rotasiY;
    _titikGeserTerakhir = detail.focalPoint;
  }

  void _ubahGestur(ScaleUpdateDetails detail) {
    final node = _modelNode;
    if (node == null) return;

    if (detail.pointerCount >= 2) {
      _skalaModel =
          (_skalaAwalGestur * detail.scale).clamp(0.08, 1.25).toDouble();
      _rotasiY = _rotasiAwalGestur + detail.rotation;
      node.scale = vector.Vector3.all(_skalaModel);
      node.eulerAngles = vector.Vector3(0, _rotasiY, 0);
      return;
    }

    final titikTerakhir = _titikGeserTerakhir;
    if (titikTerakhir == null) {
      _titikGeserTerakhir = detail.focalPoint;
      return;
    }

    final delta = detail.focalPoint - titikTerakhir;
    _titikGeserTerakhir = detail.focalPoint;

    // Geser tipis di sumbu X dan Y agar objek bisa dipindahkan tanpa meloncat.
    _posisiModel = vector.Vector3(
      (_posisiModel.x + delta.dx * 0.0012).clamp(-1.2, 1.2).toDouble(),
      (_posisiModel.y - delta.dy * 0.0012).clamp(-0.8, 0.8).toDouble(),
      _posisiModel.z,
    );
    node.position = _posisiModel;
  }

  Widget _barAtas() {
    return Positioned(
      top: 0,
      left: 0,
      right: 0,
      child: SafeArea(
        child: Padding(
          padding: const EdgeInsets.fromLTRB(12, 10, 12, 0),
          child: Row(
            children: [
              IconButton.filledTonal(
                onPressed: () => Navigator.pop(context),
                icon: const Icon(Icons.arrow_back_rounded),
              ),
              const SizedBox(width: 10),
              Expanded(
                child: Text(
                  widget.namaWisata,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 18,
                    fontWeight: FontWeight.w800,
                    shadows: [
                      Shadow(
                        blurRadius: 8,
                        color: Colors.black87,
                      ),
                    ],
                  ),
                ),
              ),
              IconButton.filledTonal(
                tooltip: 'Atur Ulang Model',
                onPressed: _resetModel,
                icon: const Icon(Icons.refresh_rounded),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _indikatorMemuat() {
    return Positioned.fill(
      child: IgnorePointer(
        child: Center(
          child: DecoratedBox(
            decoration: BoxDecoration(
              color: Colors.black.withValues(alpha: 0.62),
              borderRadius: BorderRadius.circular(24),
              border: Border.all(color: Colors.white.withValues(alpha: 0.18)),
            ),
            child: const Padding(
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 20),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  CircularProgressIndicator(color: Colors.white),
                  SizedBox(height: 16),
                  Text(
                    'Memuat model AR...',
                    style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w800,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget _panelError() {
    return Positioned(
      left: 20,
      right: 20,
      bottom: 28,
      child: SafeArea(
        child: DecoratedBox(
          decoration: BoxDecoration(
            color: Colors.black.withValues(alpha: 0.80),
            borderRadius: BorderRadius.circular(20),
            border: Border.all(color: Colors.white.withValues(alpha: 0.16)),
          ),
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Text(
              _pesanError!,
              style: const TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.w700,
              ),
            ),
          ),
        ),
      ),
    );
  }

  void _resetModel() {
    final node = _modelNode;
    if (node == null) return;

    setState(() {
      _skalaModel = 0.28;
      _rotasiY = 0;
      _posisiModel = vector.Vector3(0, -0.18, -1.25);
      node.position = _posisiModel;
      node.scale = vector.Vector3.all(_skalaModel);
      node.eulerAngles = vector.Vector3(0, _rotasiY, 0);
    });
  }
}
