/*
 * Copyright 2023 Hongen Wang All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'dart:io';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:proxypin/l10n/app_localizations.dart';
import 'package:flutter_toastr/flutter_toastr.dart';
import 'package:proxypin/network/http/content_type.dart';
import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/network/util/logger.dart';

import '../../utils/platform.dart';

const contentMap = {
  ContentType.json: Icons.data_object,
  ContentType.html: Icons.html,
  ContentType.xml: Icons.code,
  ContentType.js: Icons.javascript,
  ContentType.image: Icons.image,
  ContentType.video: Icons.video_call,
  ContentType.text: Icons.text_fields,
  ContentType.css: Icons.css,
  ContentType.font: Icons.font_download,
  ContentType.sse: Icons.stream,
};

Widget getIcon(HttpResponse? response, {Color? color}) {
  if (response == null) {
    return SizedBox(width: 18, child: Icon(Icons.question_mark, size: 16, color: color ?? Colors.green));
  }
  if (response.status.code < 0) {
    return SizedBox(width: 18, child: Icon(Icons.error, size: 16, color: color ?? Colors.red));
  }

  var contentType = response.contentType;
  if (contentType.isImage && response.body != null) {
    return Image.memory(
      Uint8List.fromList(response.body!),
      width: Platforms.isDesktop() ? 19 : 26,
      errorBuilder: (context, error, stackTrace) => Icon(Icons.image, size: 16, color: color ?? Colors.green),
    );
  }

  return SizedBox(
      width: 18, child: Icon(contentMap[contentType] ?? Icons.http, size: 16, color: color ?? Colors.green));
}

//展示报文大小
String getPackagesSize(HttpRequest request, HttpResponse? response) {
  var package = getPackage(request.packageSize);
  var responsePackage = getPackage(response?.packageSize);
  if (responsePackage.isEmpty) {
    return package;
  }
  return "$package / $responsePackage ";
}

String getPackage(int? size) {
  if (size == null) {
    return "";
  }
  if (size < 1025) {
    return "$size B";
  }

  if (size > 1024 * 1024) {
    return "${(size / 1024 / 1024).toStringAsFixed(2)} M";
  }
  return "${(size / 1024).toStringAsFixed(2)} K";
}

String copyRawRequest(HttpRequest request) {
  var sb = StringBuffer();
  var uri = request.requestUri!;
  var pathAndQuery = uri.path + (uri.query.isNotEmpty ? '?${uri.query}' : '');

  sb.writeln("${request.method.name} $pathAndQuery ${request.protocolVersion}");
  sb.write(request.headers.headerLines());
  if (request.bodyAsString.isNotEmpty) {
    sb.writeln();
    sb.write(request.bodyAsString);
  }
  return sb.toString();
}

String copyRequest(HttpRequest request, HttpResponse? response) {
  var sb = StringBuffer();
  sb.writeln("Request");
  sb.writeln("${request.method.name} ${request.requestUrl} ${request.protocolVersion}");
  sb.writeln(request.headers.headerLines());
  sb.writeln();
  sb.writeln(request.bodyAsString);

  sb.writeln("--------------------------------------------------------");
  sb.writeln();
  sb.writeln("Response");
  sb.writeln("${response?.protocolVersion} ${response?.status.code}");
  sb.writeln(response?.headers.headerLines());
  sb.writeln(response?.bodyAsString);
  return sb.toString();
}

RelativeRect menuPosition(BuildContext context) {
  final RenderBox bar = context.findRenderObject() as RenderBox;
  final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
  const Offset offset = Offset.zero;
  final RelativeRect position = RelativeRect.fromRect(
    Rect.fromPoints(
      bar.localToGlobal(bar.size.centerRight(offset), ancestor: overlay),
      bar.localToGlobal(bar.size.centerRight(offset), ancestor: overlay),
    ),
    offset & overlay.size,
  );
  return position;
}

Widget contextMenu(BuildContext context, EditableTextState editableTextState, {ContextMenuButtonItem? customItem}) {
  List<ContextMenuButtonItem> list = [
    ContextMenuButtonItem(
      onPressed: () {
        editableTextState.copySelection(SelectionChangedCause.tap);

        FlutterToastr.show(AppLocalizations.of(context)!.copied, context);
        unSelect(editableTextState);

        editableTextState.hideToolbar();
      },
      type: ContextMenuButtonType.copy,
    ),
    ContextMenuButtonItem(
      label: Localizations.localeOf(context) == const Locale.fromSubtags(languageCode: 'zh') ? '复制值' : 'Copy Value',
      onPressed: () {
        unSelect(editableTextState);
        Clipboard.setData(ClipboardData(text: editableTextState.textEditingValue.text)).then((value) {
          if (context.mounted) FlutterToastr.show(AppLocalizations.of(context)!.copied, context);
          editableTextState.hideToolbar();
        });
      },
      type: ContextMenuButtonType.custom,
    ),
    ContextMenuButtonItem(
      onPressed: () {
        editableTextState.selectAll(SelectionChangedCause.tap);
      },
      type: ContextMenuButtonType.selectAll,
    ),
  ];

  if (customItem != null) {
    list.add(customItem);
  }

  if (Platform.isIOS) {
    list.add(ContextMenuButtonItem(
      onPressed: () async {
        editableTextState.shareSelection(SelectionChangedCause.toolbar);
      },
      type: ContextMenuButtonType.share,
    ));
  }

  return AdaptiveTextSelectionToolbar.buttonItems(
    anchors: editableTextState.contextMenuAnchors,
    buttonItems: list,
  );
}

void unSelect(EditableTextState editableTextState) {
  editableTextState.userUpdateTextEditingValue(
    editableTextState.textEditingValue
        .copyWith(selection: TextSelection.collapsed(offset: editableTextState.textEditingValue.selection.baseOffset)),
    SelectionChangedCause.tap,
  );
}

///Future — skips rebuild when the resolved value equals [initialData].
Widget futureWidget<T>(Future<T> future, Widget Function(T data) toWidget, {T? initialData, bool loading = false}) {
  return _FutureWidget<T>(
    future: future,
    toWidget: toWidget,
    initialData: initialData,
    loading: loading,
  );
}

class _FutureWidget<T> extends StatefulWidget {
  final Future<T> future;
  final Widget Function(T data) toWidget;
  final T? initialData;
  final bool loading;

  const _FutureWidget({
    required this.future,
    required this.toWidget,
    this.initialData,
    this.loading = false,
  });

  @override
  State<_FutureWidget<T>> createState() => _FutureWidgetState<T>();
}

class _FutureWidgetState<T> extends State<_FutureWidget<T>> {
  T? _data;

  @override
  void initState() {
    super.initState();
    _data = widget.initialData;
    _subscribe();
  }

  @override
  void didUpdateWidget(covariant _FutureWidget<T> old) {
    super.didUpdateWidget(old);
    if (old.future != widget.future || old.initialData != widget.initialData) {
      _data = widget.initialData;
      _subscribe();
    }
  }

  void _subscribe() {
    final captured = widget.future;
    captured.then((result) {
      if (!mounted || widget.future != captured) return;
      // Result unchanged — no rebuild needed.
      if (result == _data) return;
      setState(() => _data = result);
    }).catchError((error) {
      if (mounted) logger.e(error);
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_data != null) {
      return widget.toWidget(_data as T);
    }
    return widget.loading ? const Center(child: CircularProgressIndicator()) : const SizedBox();
  }
}

Future showContextMenu(BuildContext context, Offset offset, {required List<PopupMenuEntry> items}) {
  return showMenu(
      context: context,
      position: RelativeRect.fromLTRB(
        offset.dx + 10,
        offset.dy - 50,
        offset.dx + 10,
        offset.dy - 50,
      ),
      items: items);
}

Future<T?> showConfirmDialog<T>(BuildContext context, {String? title, String? content, VoidCallback? onConfirm}) {
  title ??= AppLocalizations.of(context)!.confirmTitle;
  content ??= AppLocalizations.of(context)!.confirmContent;
  return showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text(title!, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
          content: Text(content!),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: Text(AppLocalizations.of(context)!.cancel),
            ),
            TextButton(
              onPressed: () {
                Navigator.pop(context);
                if (onConfirm != null) onConfirm();
              },
              child: Text(AppLocalizations.of(context)!.confirm),
            ),
          ],
        );
      });
}

///滚动条
ScrollController? trackingScroll(ScrollController? scrollController) {
  if (scrollController == null) {
    return null;
  }

  var trackingScroll = TrackingScrollController();
  double offset = 0;
  trackingScroll.addListener(() {
    if (trackingScroll.offset < 30 && trackingScroll.offset < offset && scrollController.offset > 0) {
      //往上滚动
      scrollController.jumpTo(scrollController.offset - max(offset - trackingScroll.offset, 15));
    } else if (trackingScroll.offset > 0 &&
        trackingScroll.offset > offset &&
        scrollController.offset < scrollController.position.maxScrollExtent) {
      //往下滚动
      scrollController.jumpTo(scrollController.offset + max(trackingScroll.offset - offset, 15));
    }

    offset = trackingScroll.offset;
  });
  return trackingScroll;
}
