import 'dart:convert';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image/image.dart' as img;
import 'package:mobile_scanner/mobile_scanner.dart';
import '../../app/route.dart';

import '../../app/constant.dart';
import '../../model/edit_person_model.dart';
import '../../model/sex_model.dart';
import '../../provider/current_user_provider.dart';
import '../../provider/no-login-scan/no_login_scan_provider.dart';
import '../../widget/customsnackbarwidget.dart';
import '../home/list_riwayat_scan_provider.dart';
import 'no_login_upload_scan_provider.dart';

class NoLoginScanScreen extends HookConsumerWidget {
  const NoLoginScanScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [
      SystemUiOverlay.bottom,
    ]);

    final judulAppBar = useState<String>("Scan QRCode & Scan KTP");
    final qrCodeExists = useState<bool>(false);
    final cameraOn = useState<bool>(false);
    final qrCodeStr = useState<String>("Scan QRCode untuk dapat merekam");
    final judulTombol = useState<String>("SCAN QR CODE");
    final awalan = useState("Info :");
    final judulPosisiHp = useState<String>("Posisi HP Landscape");

    final cameraController = useState<CameraController?>(null);
    final initializeControllerFuture = useState<Future<void>?>(null);
    final capturedImage = useState<XFile?>(null);
    final croppedImage = useState<File?>(null);
    final isLoading = useState<bool>(false);
    final isLoadingUpload = useState<bool>(false);
    final currentUser = ref.watch(currentUserProvider);
    final host = currentUser?.host ?? "";
    final userId = currentUser?.model.userId ?? "";
    final selectedResolution =
        useState<ResolutionPreset>(ResolutionPreset.medium);

    void handleBarcode(BarcodeCapture barcodes) {
      if (barcodes.barcodes.isNotEmpty) {
        final scannedBarcode =
            barcodes.barcodes.firstOrNull?.displayValue ?? "";
        if (scannedBarcode.isNotEmpty) {
          ref.read(barcodeX.notifier).state = barcodes.barcodes.first;
          qrCodeStr.value = scannedBarcode;
          awalan.value = "QrCode : ";
          qrCodeExists.value = true;
          cameraOn.value = true;
          judulTombol.value = "FOTO";
        }
      }
    }

    useEffect(() {
      Future<void> initializeCamera() async {
        final cameras = await availableCameras();
        cameraController.value = CameraController(
            cameras[0],
            // ResolutionPreset.max,
            // ResolutionPreset.medium,
            selectedResolution.value);
        initializeControllerFuture.value = cameraController.value!.initialize();
        await initializeControllerFuture.value;
        await cameraController.value!.setFlashMode(FlashMode.off);
      }

      initializeCamera();
      return null;
    }, []);

    Future<void> initializeCameraAfterChangeResolution() async {
      final cameras = await availableCameras();
      cameraController.value = CameraController(
          cameras[0],
          // ResolutionPreset.max,
          // ResolutionPreset.medium,
          selectedResolution.value);
      initializeControllerFuture.value = cameraController.value!.initialize();
      await initializeControllerFuture.value;
      await cameraController.value!.setFlashMode(FlashMode.off);
    }

    Future<File> rotateAndCropImage(File imageFile) async {
      Uint8List imageBytes = await imageFile.readAsBytes();
      img.Image? original = img.decodeImage(imageBytes);
      if (original == null) return imageFile;

      img.Image rotated = img.bakeOrientation(original);

      int width = rotated.width;
      int height = rotated.height;
      bool isPortrait = height > width;

      int cropWidth, cropHeight;

      if (isPortrait) {
        cropHeight = (height * 0.7).toInt();
        cropWidth = (cropHeight ~/ 1.59).toInt();
      } else {
        cropWidth = (width * 0.7).toInt();
        cropHeight = (cropWidth ~/ 1.59).toInt();
      }

      int left = ((width - cropWidth) ~/ 2).toInt();
      int top = ((height - cropHeight) ~/ 2).toInt();

      img.Image cropped = img.copyCrop(rotated,
          x: left, y: top, width: cropWidth, height: cropHeight);

      File croppedFile = File('${imageFile.path}_cropped.jpg');
      await croppedFile.writeAsBytes(img.encodeJpg(cropped));

      return croppedFile;
    }

    Future<File> rotateImage(File imageFile) async {
      Uint8List bytes = await imageFile.readAsBytes();
      img.Image? image = img.decodeImage(bytes);

      if (image == null) return imageFile;

      img.Image rotated = img.copyRotate(image, angle: -90);

      File rotatedFile = File('${imageFile.path}_rotated.jpg');
      await rotatedFile.writeAsBytes(img.encodeJpg(rotated));

      return rotatedFile;
    }

    Future<void> captureAndCropImage() async {
      try {
        isLoading.value = true;
        await initializeControllerFuture.value;

        // Ambil gambar dari kamera
        final image = await cameraController.value!.takePicture();
        File cropped = await rotateAndCropImage(File(image.path));

        // Rotate gambar setelah cropping
        File rotatedImage = await rotateImage(cropped);

        // Convert to grayscale
        Uint8List bytes = await rotatedImage.readAsBytes();
        img.Image? coloredImage = img.decodeImage(bytes);
        if (coloredImage != null) {
          img.Image grayscaleImage = img.grayscale(coloredImage);
          rotatedImage.writeAsBytesSync(img.encodeJpg(grayscaleImage));
        }

        // Simpan hasil yang sudah di-crop dan di-rotate
        capturedImage.value = image;
        croppedImage.value = rotatedImage;

        // post ke BE
        Uint8List finalBytes = await croppedImage.value!.readAsBytes();
        String base64String = base64Encode(finalBytes);
        ref.read(noLoginUploadScanProvider.notifier).uploadScan(
              host: host,
              base64File: base64String,
              userId: userId,
            );
      } catch (e) {
        print("Error capturing image: $e");
      } finally {
        isLoading.value = false;
      }
    }

    // listRiwayProvider
    ref.listen(listRiwayatScanProvider, (prev, next) {
      if (next is ListRiwayatScanStateLoading) {
        // isLoading.value = true;
      } else if (next is ListRiwayatScanStateError) {
        // isLoading.value = false;
        // errorMessage.value = next.message;
        snackbarWidget(
          context,
          next.message,
          snackbarType.error,
          Duration(seconds: 3),
        );
      } else if (next is ListRiwayatScanStateDone) {
        // isLoading.value = false;

        Navigator.of(context).pop();
        Navigator.of(context).pushNamed(
          editScanRoute,
        );
      }
    });

    // proses upload
    ref.listen(noLoginUploadScanProvider, (prev, next) {
      if (next is NoLoginUploadScanStateLoading) {
        isLoadingUpload.value = true;
      } else if (next is NoLoginUploadScanStateError) {
        isLoadingUpload.value = false;
        // errorMessage.value = next.message;
        print("Err : ${next.message}");
        snackbarWidget(
          context,
          next.message,
          snackbarType.error,
          Duration(seconds: 3),
        );
      } else if (next is NoLoginUploadScanStateDone) {
        isLoadingUpload.value = false;
        ref.read(selectedPersonIdx.notifier).state = next.model[0].personID;

        // set SEX
        ref.read(eSexSelected.notifier).state = SexModel(
            M_SexID: next.model[0].personSex,
            M_SexCode: "",
            m_sexname: next.model[0].m_sexname,
            M_SexNameLang: "");

        ref.read(selectedEdit.notifier).state = EditPersonModel(
          personID: next.model[0].personID,
          personNIK: next.model[0].personNIK,
          personName: next.model[0].personName,
          m_sexname: next.model[0].m_sexname,
          personDob: next.model[0].personDob,
          personSex: next.model[0].personSex,
          personUrl: next.model[0].personUrl,
        );

        ref.read(listRiwayatScanProvider.notifier).listRiwayatScan(
              host: host,
              userId: userId,
            );
      }
    });

    // loading proses upload useEffect
    useEffect(() {
      WidgetsBinding.instance.addPostFrameCallback((timestamp) {
        if (isLoadingUpload.value == true) {
          snackbarWidget(
            context,
            'Sedang Upload Foto...',
            snackbarType.warning,
            Duration(seconds: 3),
          );
        }
      });
      return () {};
    }, [isLoadingUpload.value]);

    return Scaffold(
      appBar: AppBar(
        title: Text(
          judulAppBar.value,
          style: Constant.titlePosisiHP(context: context),
        ),
        automaticallyImplyLeading: false,
        actions: [
          if (cameraOn.value == true)
            DropdownButton<ResolutionPreset>(
              value: selectedResolution.value,
              onChanged: (ResolutionPreset? newValue) {
                if (newValue != null) {
                  selectedResolution.value = newValue;
                  initializeCameraAfterChangeResolution();
                }
              },
              items: ResolutionPreset.values.map((ResolutionPreset value) {
                return DropdownMenuItem<ResolutionPreset>(
                  value: value,
                  child: Text(value.toString().split('.').last),
                );
              }).toList(),
              underline: SizedBox.shrink(),
            ),
        ],
      ),
      backgroundColor: Colors.black.withOpacity(0.5),
      body: Stack(
        children: [
          if (awalan.value == "Info :")
            SizedBox(
              width: double.infinity,
              height: Constant.getActualYPhone(
                context: context,
                y: 450,
              ),
              child: MobileScanner(
                onDetect: handleBarcode,
              ),
            ),
          // Show Qr code Str
          // Container(
          //   alignment: Alignment.center,
          //   padding: EdgeInsets.symmetric(vertical: 10),
          //   color: Constant.inputanGrey,
          //   child: Text(
          //     "${awalan.value} ${qrCodeStr.value}",
          //     style: TextStyle(color: Colors.white),
          //   ),
          // ),
          // jika camera scan ktp true show
          if (cameraOn.value == true) ...[
            SizedBox(
              height: Constant.getActualYPhone(
                context: context,
                y: 20,
              ),
            ),
            // show notif posisi HP
            Container(
              alignment: Alignment.center,
              padding: EdgeInsets.symmetric(vertical: 10),
              color: Constant.textRed,
              child: Text(
                judulPosisiHp.value,
                style: TextStyle(color: Colors.white),
              ),
            ),
            SizedBox(
              height: Constant.getActualYPhone(
                context: context,
                y: 20,
              ),
            ),
            if (cameraController.value != null && croppedImage.value == null)
              FutureBuilder<void>(
                future: initializeControllerFuture.value,
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    return CameraPreview(cameraController.value!);
                  } else {
                    return const Center(child: CircularProgressIndicator());
                  }
                },
              ),
          ],

          // jika sudah ada foto
          if (croppedImage.value != null) ...[
            Container(
              width: double.infinity,
              height: 300,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(12),
              ),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(12),
                child: Image.file(
                  croppedImage.value!,
                  fit: BoxFit.contain,
                ),
              ),
            ),
          ] else ...[
            // bingkai foto
            Positioned.fill(
              child: CustomPaint(
                painter: OverlayPainter(),
              ),
            ),
          ],
          // loading
          if (isLoading.value)
            Positioned.fill(
              child: Container(
                color: Colors.black.withOpacity(0.5),
                child: const Center(
                  child: CircularProgressIndicator(
                    color: Colors.white,
                  ),
                ),
              ),
            ),
        ],
      ),
      bottomNavigationBar: BottomAppBar(
        height: Constant.getActualYPhone(
          context: context,
          y: 100,
        ),
        shape: const CircularNotchedRectangle(),
        child: Row(
          children: [
            ElevatedButton.icon(
              onPressed: () {
                capturedImage.value = null;
                croppedImage.value = null;

                ref.read(barcodeX.notifier).state = Barcode();
                qrCodeExists.value = false;
                judulTombol.value = "SCAN QR CODE";
                qrCodeStr.value = "Scan QRCode untuk dapat merekam";
                cameraOn.value = false;
                awalan.value = "Info :";
                Navigator.of(context).pop();
              },
              icon: Icon(
                Icons.arrow_back,
                size: 17,
                color: Constant.textWhite,
              ),
              label: Text(
                'Kembali',
                style: Constant.cardText(context: context).copyWith(
                  color: Constant.textWhite,
                ),
              ),
              style: ElevatedButton.styleFrom(
                backgroundColor: Constant.textCardGrey,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
                elevation: 8,
                shadowColor: Constant.bgButton.withOpacity(0.24),
              ),
            ),
            const Spacer(),
            // scan
            ElevatedButton.icon(
              onPressed: captureAndCropImage,
              icon: Icon(
                Icons.camera,
                size: 17,
                color: Constant.textWhite,
              ),
              label: Text(
                judulTombol.value,
                style: Constant.cardText(context: context).copyWith(
                  color: Constant.textWhite,
                ),
              ),
              style: ElevatedButton.styleFrom(
                backgroundColor: Constant.bgButton,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
                elevation: 8,
                shadowColor: Constant.bgButton.withOpacity(0.24),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class OverlayPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.black.withOpacity(0.6)
      ..style = PaintingStyle.fill;

    final borderPaint = Paint()
      ..color = Colors.yellow
      ..strokeWidth = 4
      ..style = PaintingStyle.stroke;

    double boxHeight = size.height * 0.7;
    double boxWidth = boxHeight / 1.59;

    double left = (size.width - boxWidth) / 2;
    double top = (size.height - boxHeight) / 2;

    Path path = Path()
      ..addRect(Rect.fromLTWH(0, 0, size.width, size.height))
      ..addRect(Rect.fromLTWH(left, top, boxWidth, boxHeight))
      ..fillType = PathFillType.evenOdd;

    canvas.drawPath(path, paint);
    canvas.drawRect(Rect.fromLTWH(left, top, boxWidth, boxHeight), borderPaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}
