import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:guru_assistant/data/setting.dart';
import 'package:guru_utils/log/log.dart';
import 'package:guru_utils/extensions/extensions.dart';
import 'package:guru_widgets/pages/settings/guru_settings_page.dart' as guru;
import 'package:guru_widgets/theme/guru_theme.dart';
import 'package:guru_utils/ads/data/ads_model.dart';
import 'package:flutter/src/services/clipboard.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:guru_app/ads/ads_manager.dart';
import 'package:guru_app/property/settings/guru_settings.dart';
import 'package:guru_app/ads/core/ads.dart';
import 'package:guru_app/ads/applovin/banner/applovin_banner_ads.dart';
import 'package:guru_app/ads/applovin/interstitial/applovin_interstitial_ads.dart';
import 'package:guru_app/ads/applovin/rewarded/applovin_rewarded_ads.dart';
import 'package:guru_widgets/guru_widgets.dart';
import 'package:guru_utils/ads/handler/ads_handler.dart';
import 'package:guru_widgets/tile/guru_list_tile.dart';

import 'keywords_test_controller.dart';

/// Created by Haoyi on 2023/8/18

class KeywordsTestPage extends GetWidget<GuruKeywordsTestController> {
  const KeywordsTestPage({super.key});

  @override
  Widget build(BuildContext context) {
    return guru.GuruSettingsPage(
      items: [
        guru.WidgetSetting(
            widget: const KeywordAdsListTile(
          adUnitId: AdUnitId(android: "c6b418becb8abd43", ios: "62d52c7e556bc423"),
          adType: AdType.banner,
        )),
        guru.WidgetSetting(
            widget: const KeywordAdsListTile(
          adUnitId: AdUnitId(android: "bc16ace919c9dde9", ios: "0708364e378f1a00"),
          adType: AdType.interstitial,
        )),
        guru.WidgetSetting(
            widget: const KeywordAdsListTile(
          adUnitId: AdUnitId(android: "4ec9e2cdd1b368c3", ios: "1fdac0946dcee04d"),
          adType: AdType.rewarded,
        )),
        guru.GroupSetting(title: "KEYWORDS RAW DATA", items: [
          guru.StreamSetting(controller.observableKeywords, (context, snapshot) {
            final keywords = snapshot.data ?? <String, String>{};
            Log.d("keywords changed!:$keywords");
            final guruTheme = GuruTheme.of(context);
            final tileTheme = guruTheme.listTileTheme;
            final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
            final colorScheme = guruTheme.colorScheme;
            return Material(
                color: tileTheme.backgroundColor ?? colorScheme.containerColor ?? Colors.white,
                child: Ink(
                    height: designSpec.measuredSize.height * 1.5,
                    child: InkWell(
                        onTap: () {
                          Clipboard.setData(ClipboardData(text: keywords.toString()));
                        },
                        child: Padding(
                          padding: designSpec.itemPadding,
                          child: SizedBox.expand(
                            child: AutoSizeText(keywords.toString(),
                                minFontSize: 10,
                                maxLines: 3,
                                style: TextStyle(
                                    fontSize: designSpec.titleFontSize,
                                    fontWeight: GuruTheme.fwMedium,
                                    fontStyle: FontStyle.italic,
                                    color: tileTheme.primaryContentColor ??
                                        colorScheme.primaryContentColor ??
                                        Colors.black)),
                          ),
                        ))));
          })
        ]),
        guru.GroupSetting(
          title: "DEFAULT CONFIG",
          items: [
            guru.StreamSetting(KeywordsTestSetting.instance.appVersionEnabled.observe(),
                (context, snapshot) {
              final enabled = snapshot.data ?? false;
              return DropdownSwitchListTile<String>(
                title: "app_version",
                selectableValues: [GuruSettings.instance.version.get()],
                selected: KeywordsTestSetting.instance.appVersion,
                enabled: enabled,
                onSelected: (selected) {
                  if (enabled && selected != null) {
                    KeywordsTestSetting.instance.appVersion.set(selected);
                    AdsManager.instance.setKeyword("app_version", selected, debugForce: true);
                  }
                },
                onChanged: (enabled) {
                  KeywordsTestSetting.instance.appVersionEnabled.set(enabled);
                  Log.d("set app_version enabled $enabled");
                  if (enabled) {
                    AdsManager.instance.setKeyword(
                        "app_version", KeywordsTestSetting.instance.appVersion.get().toString(),
                        debugForce: true);
                  } else {
                    AdsManager.instance.removeKeyword("app_version", debugForce: true);
                  }
                },
              );
            }),
            guru.StreamSetting(KeywordsTestSetting.instance.paidEnabled.observe(),
                (context, snapshot) {
              final enabled = snapshot.data ?? false;

              return DropdownSwitchListTile<bool>(
                title: "paid",
                selectableValues: const [true, false],
                selected: KeywordsTestSetting.instance.paidValue,
                enabled: enabled,
                onSelected: (selected) {
                  if (enabled && selected != null) {
                    KeywordsTestSetting.instance.paidValue.set(selected);
                    AdsManager.instance.setKeyword("paid", selected.toString(), debugForce: true);
                  }
                },
                onChanged: (enabled) {
                  KeywordsTestSetting.instance.paidEnabled.set(enabled);
                  if (enabled) {
                    AdsManager.instance.setKeyword(
                        "paid", KeywordsTestSetting.instance.paidValue.get().toString(),
                        debugForce: true);
                  } else {
                    AdsManager.instance.removeKeyword("paid", debugForce: true);
                  }
                },
              );
            }),
            guru.StreamSetting(KeywordsTestSetting.instance.ltEnabled.observe(),
                (context, snapshot) {
              final enabled = snapshot.data ?? false;

              return DropdownSwitchListTile<int>(
                title: "lt(days)",
                selectableValues: AdsManager.ltSamples,
                selected: KeywordsTestSetting.instance.ltValue,
                enabled: enabled,
                onSelected: (selected) {
                  Log.d("onSelected:$selected");
                  if (enabled && selected != null) {
                    KeywordsTestSetting.instance.ltValue.set(selected);
                    AdsManager.instance.setKeyword("lt", selected.toString(), debugForce: true);
                  }
                },
                onChanged: (enabled) {
                  KeywordsTestSetting.instance.ltEnabled.set(enabled);
                  if (enabled) {
                    AdsManager.instance.setKeyword(
                        "lt", KeywordsTestSetting.instance.ltValue.get().toString(),
                        debugForce: true);
                  } else {
                    AdsManager.instance.removeKeyword("lt", debugForce: true);
                  }
                },
              );
            })
          ],
        )
      ],
      subpage: true,
    );
  }
}

class KeywordAdsListTile extends StatefulWidget {
  final AdUnitId adUnitId;
  final AdType adType;

  const KeywordAdsListTile({required this.adUnitId, required this.adType, Key? key})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => KeywordAdsListTileState();
}

class KeywordAdsListTileState extends State<KeywordAdsListTile> {
  final BehaviorSubject<bool> testingSubject = BehaviorSubject.seeded(false);
  final BehaviorSubject<String> waterfallNameSubject = BehaviorSubject.seeded("Unknown");

  Stream<String> get observableWaterfallName => waterfallNameSubject.stream;

  Stream<bool> get observableTesting => testingSubject.stream;

  SingleAds? currentAds;

  Timer? timeoutTimer;

  String getAdsTypeName() {
    switch (widget.adType) {
      case AdType.banner:
        return "Banner";
      case AdType.interstitial:
        return "Interstitial";
      case AdType.rewarded:
        return "Rewarded";
      default:
        return "Unknown";
    }
  }

  SingleAds? createAds() {
    switch (widget.adType) {
      case AdType.banner:
        return ApplovinBannerAds.create(widget.adUnitId, null);
      case AdType.interstitial:
        return ApplovinInterstitialAds.create(widget.adUnitId, null);
      case AdType.rewarded:
        return ApplovinRewardedAds.create(widget.adUnitId);
      default:
        return null;
    }
  }

  void testAds() {
    cancelTest();
    currentAds = createAds()
      ?..addObserver(AdsLifecycleObserverDelegate(
        onAdLoadedCallback: (bundle) {
          Log.d("onAdLoadedCallback");
          final waterfallName = bundle.getString("ad_waterfall_name", defValue: "Unknown");
          waterfallNameSubject.addIfChanged(waterfallName);
        },
        onAdLoadFailedCallback: (bundle) {
          Log.d("onAdLoadFailedCallback");
          final waterfallName = bundle.getString("ad_waterfall_name", defValue: "Unknown");
          waterfallNameSubject.addIfChanged(waterfallName);
        },
      ))
      ..init()
      ..load();
    timeoutTimer = Timer(const Duration(seconds: 30), () {
      currentAds?.dispose();
      testingSubject.addIfChanged(false);
      currentAds = null;
    });
    testingSubject.addIfChanged(true);
  }

  void cancelTest() {
    currentAds?.dispose();
    timeoutTimer?.cancel();
    currentAds = null;
    testingSubject.addIfChanged(false);
  }

  @override
  Widget build(BuildContext context) {
    final guruTheme = GuruTheme.of(context);
    final tileTheme = guruTheme.listTileTheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    final colorScheme = guruTheme.colorScheme;
    final items = <Widget>[];

    items.add(Expanded(
      flex: 1,
      child: Padding(
          padding: designSpec.titlePadding,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(getAdsTypeName(),
                  style: TextStyle(
                      fontSize: designSpec.titleFontSize,
                      fontWeight: GuruTheme.fwMedium,
                      color: tileTheme.primaryContentColor ??
                          colorScheme.primaryContentColor ??
                          Colors.black)),
              Text(widget.adUnitId.id,
                  style: TextStyle(
                      fontStyle: FontStyle.italic,
                      fontSize: designSpec.summaryFontSize,
                      color: tileTheme.secondaryContentColor ??
                          colorScheme.secondaryContentColor ??
                          Colors.grey))
            ],
          )),
    ));

    items.add(Expanded(
      flex: 1,
      child: Padding(
          padding: designSpec.titlePadding,
          child: StreamBuilder<String>(
              stream: observableWaterfallName,
              builder: (context, snapshot) {
                return AutoSizeText(snapshot.data ?? "Unknown",
                    minFontSize: 10,
                    maxLines: 1,
                    style: TextStyle(
                        fontSize: designSpec.titleFontSize,
                        fontWeight: GuruTheme.fwMedium,
                        color: tileTheme.primaryContentColor ??
                            colorScheme.primaryContentColor ??
                            Colors.black));
              })),
    ));

    items.add(StreamBuilder<bool>(
        stream: observableTesting,
        builder: (context, snapshot) {
          final testing = snapshot.data == true;
          return GuruButton(
            size: const Size(64, 28),
            onPressed: () async {
              if (testing) {
                cancelTest();
              } else {
                testAds();
              }
            },
            child: Center(
                child: AutoSizeText(
              testing ? "CANCEL" : "TEST",
              minFontSize: 8,
              style:
                  const TextStyle(fontSize: 10, fontWeight: FontWeight.w600, color: Colors.white),
            )),
          );
        }));
    return Material(
        color: tileTheme.backgroundColor ?? colorScheme.containerColor ?? Colors.white,
        child: SizedBox(
            height: designSpec.measuredSize.height,
            child: Padding(
              padding: designSpec.switchItemPadding,
              child: Row(mainAxisSize: MainAxisSize.max, children: items),
            )));
  }
}

class DropdownSwitchListTile<T> extends GuruTile {
  final String title;
  final bool enabled;
  final List<T> selectableValues;
  final SettingData<T> selected;
  final ValueChanged<bool>? onChanged;
  final ValueChanged<T?>? onSelected;

  const DropdownSwitchListTile(
      {required this.title,
      required this.selectableValues,
      required this.selected,
      required this.enabled,
      this.onChanged,
      this.onSelected,
      Key? key})
      : super(key: key);

  Widget buildSwitch(GuruThemeData guruTheme) {
    final iconScheme = guruTheme.iconScheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    if (iconScheme.switchOnIcon != null && iconScheme.switchOffIcon != null) {
      return Image.asset(
        enabled ? iconScheme.switchOnIcon! : iconScheme.switchOffIcon!,
        width: designSpec.switchBarSize.width,
        height: designSpec.switchBarSize.height,
      );
    } else {
      return SizedBox(
          width: designSpec.switchBarSize.width,
          height: designSpec.switchBarSize.height,
          child: Switch(
            value: enabled,
            onChanged: (value) {
              onChanged?.call(value);
            },
          ));
    }
  }

  Widget buildDropdown() {
    return StreamBuilder<T>(
        stream: selected.observe(),
        builder: (context, snapshot) {
          return DropdownButton<T>(
            value: snapshot.data,
            dropdownColor: const Color.fromARGB(255, 72, 72, 72),
            style: const TextStyle(color: Colors.white),
            underline: Container(),
            onChanged: (T? value) {
              selected.set(value);
              onSelected?.call(value);
            },
            items: selectableValues.map<DropdownMenuItem<T>>((T value) {
              return DropdownMenuItem<T>(
                value: value,
                child: Text(value.toString()),
              );
            }).toList(),
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    final guruTheme = GuruTheme.of(context);
    final tileTheme = guruTheme.listTileTheme;
    final designSpec = guruTheme.designSpec.pageListTileDesignSpec;
    final colorScheme = guruTheme.colorScheme;
    final items = <Widget>[];

    items.add(Expanded(
      flex: 3,
      child: Padding(
          padding: designSpec.titlePadding,
          child: AutoSizeText(title,
              minFontSize: 10,
              maxLines: 1,
              style: TextStyle(
                  fontSize: designSpec.titleFontSize,
                  fontWeight: GuruTheme.fwMedium,
                  color: tileTheme.primaryContentColor ??
                      colorScheme.primaryContentColor ??
                      Colors.black))),
    ));
    items.add(const VerticalDivider(
      thickness: 1,
      indent: 10,
      endIndent: 10,
      color: Colors.grey,
    ));
    items.add(Expanded(
        flex: 4, child: Padding(padding: designSpec.titlePadding, child: buildDropdown())));
    items.add(buildSwitch(guruTheme));
    return Material(
        color: tileTheme.backgroundColor ?? colorScheme.containerColor ?? Colors.white,
        child: Ink(
            height: designSpec.measuredSize.height,
            child: InkWell(
                onTap: () {
                  onChanged?.call(!enabled);
                },
                child: Padding(
                  padding: designSpec.switchItemPadding,
                  child: Row(mainAxisSize: MainAxisSize.max, children: items),
                ))));
  }
}
