import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as image;
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:webview_flutter/webview_flutter.dart';
// ignore: depend_on_referenced_packages
import 'package:webview_flutter_android/webview_flutter_android.dart';
// ignore: depend_on_referenced_packages
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';

import '../../../common/config.dart';
import '../../../common/constants.dart';
import '../../../common/tools.dart';
import 'webview_interface.dart';
import 'webview_mixin.dart';

class WebviewFlutter extends WebviewInterface {
  const WebviewFlutter({
    super.key,
    super.title,
    super.url,
    super.data,
    super.appBar,
    super.onPageFinished,
    super.shouldPreventNavigator,
    super.onClosed,
    super.script,
    super.headers,
    super.enableForward,
    super.enableBackward,
    super.enableClose,
    super.routeName,
    super.hideNewAppBar,
    super.showAppBar,
    super.showLoading,
    super.webViewDelegateController,
  });

  @override
  StateWebviewFlutter createState() => StateWebviewFlutter();
}

class StateWebviewFlutter extends StateWebviewInterface<WebviewFlutter>
    with WebviewMixin {
  int selectedIndex = 1;
  bool isLoading = true;

  late final WebViewController _controller;
  late final PlatformWebViewControllerCreationParams params;

  void onFinishLoading() {
    setState(() {
      selectedIndex = 0;
    });
    _controller.runJavaScript(
      widget.script.isEmptyOrNull
          ? kWebViewConfig.webViewScript
          : widget.script,
    );
  }

  @override
  Future<bool> onTapBackButton(BuildContext buildContext) async {
    var canGoBack = await _controller.canGoBack();
    if (canGoBack) {
      await _controller.goBack();
      return true;
    }

    if (canPop) {
      widget.onClosed?.call();
      Navigator.of(context).pop();
      return true;
    }

    return false;
  }

  @override
  Future<bool> onTapForwardButton(BuildContext buildContext) async {
    final canGoForward = await _controller.canGoForward();
    if (canGoForward == true) {
      await _controller.goForward();
      return true;
    }

    return false;
  }

  @override
  void onTapCloseButton() async {
    widget.onClosed?.call();

    if (canPop) {
      Navigator.of(context).pop();
    }
  }

  void _handleGeolocationPermissionListener() async {
    if (isAndroid) {
      final androidController =
          _controller.platform as AndroidWebViewController;
      await androidController.setGeolocationPermissionsPromptCallbacks(
        onShowPrompt: (request) async {
          var status = await Permission.locationWhenInUse.status;

          if (status.isDenied) {
            // For the first time if user have never asked for permission yet,
            // this status will return [PermissionStatus.denied].
            status = await Permission.locationWhenInUse.request();
          } else if (status.isPermanentlyDenied) {
            // For the next time if user already denied permission, they
            // must go to app settings to allow permission manually again.
            await openAppSettings();
          }

          return GeolocationPermissionsResponse(
            allow: status.isGranted,
            retain: true,
          );
        },
      );
    }
  }

  void _handleCameraPermissionListener() async {
    if (isAndroid) {
      final androidController =
          _controller.platform as AndroidWebViewController;

      await androidController.setOnPlatformPermissionRequest(
        (request) => _permissionRequest(request),
      );
    }
  }

  Future<void> _permissionRequest(
    PlatformWebViewPermissionRequest request,
  ) async {
    final types = request.types;
    var hasCamera = types.contains(WebViewPermissionResourceType.camera);
    var hasMic = types.contains(WebViewPermissionResourceType.microphone);

    // Check camera and microphone permissions if requested
    if (hasCamera) {
      final status = await Permission.camera.request();
      if (!status.isGranted) {
        await request.deny();
        return;
      }
    }
    if (hasMic) {
      final status = await Permission.microphone.request();
      if (!status.isGranted) {
        await request.deny();
        return;
      }
    }

    // Grant the permission request
    // Other permission types (e.g., protected media, MIDI) are granted by default
    // Geolocation is handled separately in _handleGeolocationPermissionListener
    await request.grant();
  }

  void _addFileSelectionListener() async {
    if (isAndroid) {
      final androidController =
          _controller.platform as AndroidWebViewController;
      await androidController.setOnShowFileSelector(_androidFilePicker);
    }
  }

  // Return a list of Uris
  Future<List<String>> _androidFilePicker(
    final FileSelectorParams params,
  ) async {
    final files = await showModalBottomSheet(
      context: context,
      builder: (BuildContext _) {
        return SafeArea(
          child: Wrap(
            children: <Widget>[
              ListTile(
                leading: const Icon(Icons.photo_library),
                title: const Text('Gallery'),
                onTap: () {
                  final image = imagePicker(ImageSource.gallery);
                  Navigator.of(context).pop(image);
                },
              ),
              ListTile(
                leading: const Icon(Icons.photo_camera),
                title: const Text('Camera'),
                onTap: () {
                  final image = imagePicker(ImageSource.camera);
                  Navigator.of(context).pop(image);
                },
              ),
              ListTile(
                leading: const Icon(Icons.folder),
                title: const Text('File'),
                onTap: () {
                  final image = filePicker(params);
                  Navigator.of(context).pop(image);
                },
              ),
            ],
          ),
        );
      },
    );

    return files ?? [];
  }

  Future<List<String>> filePicker(final FileSelectorParams params) async {
    try {
      if (params.mode == FileSelectorMode.openMultiple) {
        final attachments = await FilePicker.platform.pickFiles(
          allowMultiple: true,
        );
        if (attachments == null) return [];

        return attachments.files
            .where((element) => element.path != null)
            .map((e) => File(e.path!).uri.toString())
            .toList();
      } else {
        final attachment = await FilePicker.platform.pickFiles();
        if (attachment == null || attachment.files.single.path == null) {
          return [];
        }
        var file = File(attachment.files.single.path!);
        return [file.uri.toString()];
      }
    } catch (e) {
      return [];
    }
  }

  Future<List<String>> imagePicker(ImageSource source) async {
    final photo = await ImageTools.pickImage(source: source);
    if (photo == null) {
      return [];
    }

    final imageData = await photo.readAsBytes();
    final decodedImage = image.decodeImage(imageData)!;
    final scaledImage = image.copyResize(decodedImage, width: 500);
    final jpg = image.encodeJpg(scaledImage, quality: 90);

    final filePath = (await getTemporaryDirectory()).uri.resolve(
      './image_${DateTime.now().microsecondsSinceEpoch}.jpg',
    );
    final file = await File.fromUri(filePath).create(recursive: true);
    await file.writeAsBytes(jpg, flush: true);

    return [file.uri.toString()];
  }

  @override
  void initState() {
    if (WebViewPlatform.instance is WebKitWebViewPlatform) {
      params = WebKitWebViewControllerCreationParams(
        allowsInlineMediaPlayback: true,
        mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
      );
    } else {
      params = const PlatformWebViewControllerCreationParams();
    }
    _controller = WebViewController.fromPlatformCreationParams(params)
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setBackgroundColor(const Color(0x00000000));
    if (url?.isNotEmpty ?? false) {
      _controller
        ..setNavigationDelegate(
          NavigationDelegate(
            onProgress: (int progress) {
              if (progress == 100) {
                onFinishLoading();
              }
            },
            onNavigationRequest: (NavigationRequest request) async {
              final url = request.url;

              // Only check main frame navigation.
              // Do not handle subframe navigation
              if (!request.isMainFrame) {
                return NavigationDecision.navigate;
              }

              // Download image from data url
              if (url.startsWith('data:image')) {
                await saveBase64ToImage(request.url);
                return NavigationDecision.prevent;
              }

              final prevent =
                  await widget.shouldPreventNavigator?.call(url) ?? false;
              if (prevent) {
                printLog('[WebviewFlutter] should prevent navigator: $url');
                return NavigationDecision.prevent;
              }
              return NavigationDecision.navigate;
            },
            onPageStarted: (String url) {},
            onPageFinished: (String url) {},
            onUrlChange: (urlChange) {
              final url = urlChange.url;
              if (url != null) {
                widget.onPageFinished?.call(url);
              }
            },
            onWebResourceError: (WebResourceError error) {},
          ),
        )
        ..loadRequest(Uri.parse(url.toString()), headers: widget.headers ?? {});
    } else if (widget.data?.isNotEmpty ?? false) {
      _controller
        ..setNavigationDelegate(
          NavigationDelegate(
            onProgress: (int progress) {
              if (progress == 100) {
                onFinishLoading();
              }
            },
            onNavigationRequest: (NavigationRequest request) async {
              final url = request.url;

              // Only check main frame navigation.
              // Do not handle subframe navigation
              if (!request.isMainFrame) {
                return NavigationDecision.navigate;
              }

              // Download image from data url
              if (request.url.startsWith('data:image')) {
                await saveBase64ToImage(request.url);
                return NavigationDecision.prevent;
              }

              final prevent =
                  await widget.shouldPreventNavigator?.call(url) ?? false;
              if (prevent) {
                printLog('[WebviewFlutter] should prevent navigator: $url');
                return NavigationDecision.prevent;
              }
              return NavigationDecision.navigate;
            },
          ),
        )
        ..loadHtmlString('${widget.data}');
    }

    // if (controller.platform is AndroidWebViewController) {
    //   AndroidWebViewController.enableDebugging(true);
    //   (controller.platform as AndroidWebViewController)
    //       .setMediaPlaybackRequiresUserGesture(false);
    // }

    _addFileSelectionListener();

    _handleGeolocationPermissionListener();
    _handleCameraPermissionListener();

    super.initState();
  }

  @override
  void dispose() {
    if (kWebViewConfig.alwaysClearWebViewCache) {
      _controller.clearCache();
    }
    if (kWebViewConfig.alwaysClearWebViewCookie) {
      WebViewCookieManager().clearCookies();
    }
    super.dispose();
  }

  @override
  Widget renderWebview() {
    return IndexedStack(
      index: selectedIndex,
      children: [
        Builder(
          builder: (BuildContext context) {
            return WebViewWidget(
              controller: _controller,
              gestureRecognizers: <Factory<VerticalDragGestureRecognizer>>{}
                ..add(
                  const Factory<VerticalDragGestureRecognizer>(
                    VerticalDragGestureRecognizer.new,
                  ),
                ),
            );
          },
        ),
        if (widget.showLoading)
          Center(child: kLoadingWidget(context))
        else
          const SizedBox(),
      ],
    );
  }
}
