import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/providers/config.dart';
import 'package:fl_clash/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class OverrideItem extends ConsumerWidget {
  const OverrideItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final override = ref.watch(overrideDnsProvider);
    return ListItem.switchItem(
      title: Text(appLocalizations.overrideDns),
      subtitle: Text(appLocalizations.overrideDnsDesc),
      delegate: SwitchDelegate(
        value: override,
        onChanged: (bool value) async {
          ref.read(overrideDnsProvider.notifier).value = value;
        },
      ),
    );
  }
}

class StatusItem extends ConsumerWidget {
  const StatusItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final enable =
        ref.watch(patchClashConfigProvider.select((state) => state.dns.enable));
    return ListItem.switchItem(
      title: Text(appLocalizations.status),
      subtitle: Text(appLocalizations.statusDesc),
      delegate: SwitchDelegate(
        value: enable,
        onChanged: (bool value) async {
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(enable: value));
        },
      ),
    );
  }
}

class ListenItem extends ConsumerWidget {
  const ListenItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final listen =
        ref.watch(patchClashConfigProvider.select((state) => state.dns.listen));
    return ListItem.input(
      title: Text(appLocalizations.listen),
      subtitle: Text(listen),
      delegate: InputDelegate(
        title: appLocalizations.listen,
        value: listen,
        validator: (value) {
          if (value == null || value.isEmpty) {
            return appLocalizations.emptyTip(appLocalizations.listen);
          }
          return null;
        },
        onChanged: (String? value) {
          if (value == null) {
            return;
          }
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(listen: value));
        },
      ),
    );
  }
}

class PreferH3Item extends ConsumerWidget {
  const PreferH3Item({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final preferH3 = ref
        .watch(patchClashConfigProvider.select((state) => state.dns.preferH3));
    return ListItem.switchItem(
      title: const Text("PreferH3"),
      subtitle: Text(appLocalizations.preferH3Desc),
      delegate: SwitchDelegate(
        value: preferH3,
        onChanged: (bool value) async {
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(preferH3: value));
        },
      ),
    );
  }
}

class IPv6Item extends ConsumerWidget {
  const IPv6Item({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final ipv6 = ref.watch(
      patchClashConfigProvider.select((state) => state.dns.ipv6),
    );
    return ListItem.switchItem(
      title: const Text("IPv6"),
      delegate: SwitchDelegate(
        value: ipv6,
        onChanged: (bool value) async {
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(ipv6: value));
        },
      ),
    );
  }
}

class RespectRulesItem extends ConsumerWidget {
  const RespectRulesItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final respectRules = ref.watch(
      patchClashConfigProvider.select((state) => state.dns.respectRules),
    );
    return ListItem.switchItem(
      title: Text(appLocalizations.respectRules),
      subtitle: Text(appLocalizations.respectRulesDesc),
      delegate: SwitchDelegate(
        value: respectRules,
        onChanged: (bool value) async {
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(respectRules: value));
        },
      ),
    );
  }
}

class DnsModeItem extends ConsumerWidget {
  const DnsModeItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final enhancedMode = ref.watch(
      patchClashConfigProvider.select((state) => state.dns.enhancedMode),
    );
    return ListItem<DnsMode>.options(
      title: Text(appLocalizations.dnsMode),
      subtitle: Text(enhancedMode.name),
      delegate: OptionsDelegate(
        title: appLocalizations.dnsMode,
        options: DnsMode.values,
        onChanged: (value) {
          if (value == null) {
            return;
          }
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(enhancedMode: value));
        },
        textBuilder: (dnsMode) => dnsMode.name,
        value: enhancedMode,
      ),
    );
  }
}

class FakeIpRangeItem extends ConsumerWidget {
  const FakeIpRangeItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final fakeIpRange = ref.watch(
      patchClashConfigProvider.select((state) => state.dns.fakeIpRange),
    );
    return ListItem.input(
      title: Text(appLocalizations.fakeipRange),
      subtitle: Text(fakeIpRange),
      delegate: InputDelegate(
        title: appLocalizations.fakeipRange,
        value: fakeIpRange,
        validator: (value) {
          if (value == null || value.isEmpty) {
            return appLocalizations.emptyTip(appLocalizations.fakeipRange);
          }
          return null;
        },
        onChanged: (String? value) {
          if (value == null) {
            return;
          }
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(fakeIpRange: value));
        },
      ),
    );
  }
}

class FakeIpFilterItem extends StatelessWidget {
  const FakeIpFilterItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.fakeipFilter),
      delegate: OpenDelegate(
        blur: false,
        title: appLocalizations.fakeipFilter,
        widget: Consumer(
          builder: (_, ref, __) {
            final fakeIpFilter = ref.watch(
              patchClashConfigProvider
                  .select((state) => state.dns.fakeIpFilter),
            );
            return ListInputPage(
              title: appLocalizations.fakeipFilter,
              items: fakeIpFilter,
              titleBuilder: (item) => Text(item),
              onChange: (items) {
                ref
                    .read(patchClashConfigProvider.notifier)
                    .updateState((state) => state.copyWith.dns(
                          fakeIpFilter: List.from(items),
                        ));
              },
            );
          },
        ),
      ),
    );
  }
}

class DefaultNameserverItem extends StatelessWidget {
  const DefaultNameserverItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.defaultNameserver),
      subtitle: Text(appLocalizations.defaultNameserverDesc),
      delegate: OpenDelegate(
        blur: false,
        title: appLocalizations.defaultNameserver,
        widget: Consumer(builder: (_, ref, __) {
          final defaultNameserver = ref.watch(
            patchClashConfigProvider
                .select((state) => state.dns.defaultNameserver),
          );
          return ListInputPage(
            title: appLocalizations.defaultNameserver,
            items: defaultNameserver,
            titleBuilder: (item) => Text(item),
            onChange: (items) {
              ref.read(patchClashConfigProvider.notifier).updateState(
                    (state) => state.copyWith.dns(
                      defaultNameserver: List.from(items),
                    ),
                  );
            },
          );
        }),
      ),
    );
  }
}

class NameserverItem extends StatelessWidget {
  const NameserverItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.nameserver),
      subtitle: Text(appLocalizations.nameserverDesc),
      delegate: OpenDelegate(
        title: appLocalizations.nameserver,
        blur: false,
        widget: Consumer(builder: (_, ref, __) {
          final nameserver = ref.watch(
            patchClashConfigProvider.select((state) => state.dns.nameserver),
          );
          return ListInputPage(
            title: appLocalizations.nameserver,
            items: nameserver,
            titleBuilder: (item) => Text(item),
            onChange: (items) {
              ref.read(patchClashConfigProvider.notifier).updateState(
                    (state) => state.copyWith.dns(
                      nameserver: List.from(items),
                    ),
                  );
            },
          );
        }),
      ),
    );
  }
}

class UseHostsItem extends ConsumerWidget {
  const UseHostsItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final useHosts = ref.watch(
      patchClashConfigProvider.select((state) => state.dns.useHosts),
    );
    return ListItem.switchItem(
      title: Text(appLocalizations.useHosts),
      delegate: SwitchDelegate(
        value: useHosts,
        onChanged: (bool value) async {
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(useHosts: value));
        },
      ),
    );
  }
}

class UseSystemHostsItem extends ConsumerWidget {
  const UseSystemHostsItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final useSystemHosts = ref.watch(
      patchClashConfigProvider.select((state) => state.dns.useSystemHosts),
    );
    return ListItem.switchItem(
      title: Text(appLocalizations.useSystemHosts),
      delegate: SwitchDelegate(
        value: useSystemHosts,
        onChanged: (bool value) async {
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns(
                    useSystemHosts: value,
                  ));
        },
      ),
    );
  }
}

class NameserverPolicyItem extends StatelessWidget {
  const NameserverPolicyItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.nameserverPolicy),
      subtitle: Text(appLocalizations.nameserverPolicyDesc),
      delegate: OpenDelegate(
        blur: false,
        title: appLocalizations.nameserverPolicy,
        widget: Consumer(builder: (_, ref, __) {
          final nameserverPolicy = ref.watch(
            patchClashConfigProvider
                .select((state) => state.dns.nameserverPolicy),
          );
          return MapInputPage(
            title: appLocalizations.nameserverPolicy,
            map: nameserverPolicy,
            titleBuilder: (item) => Text(item.key),
            subtitleBuilder: (item) => Text(item.value),
            onChange: (value) {
              ref.read(patchClashConfigProvider.notifier).updateState(
                    (state) => state.copyWith.dns(
                      nameserverPolicy: value,
                    ),
                  );
            },
          );
        }),
      ),
    );
  }
}

class ProxyServerNameserverItem extends StatelessWidget {
  const ProxyServerNameserverItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.proxyNameserver),
      subtitle: Text(appLocalizations.proxyNameserverDesc),
      delegate: OpenDelegate(
        blur: false,
        title: appLocalizations.proxyNameserver,
        widget: Consumer(
          builder: (_, ref, __) {
            final proxyServerNameserver = ref.watch(
              patchClashConfigProvider
                  .select((state) => state.dns.proxyServerNameserver),
            );
            return ListInputPage(
              title: appLocalizations.proxyNameserver,
              items: proxyServerNameserver,
              titleBuilder: (item) => Text(item),
              onChange: (items) {
                ref.read(patchClashConfigProvider.notifier).updateState(
                      (state) => state.copyWith.dns(
                        proxyServerNameserver: List.from(items),
                      ),
                    );
              },
            );
          },
        ),
      ),
    );
  }
}

class FallbackItem extends StatelessWidget {
  const FallbackItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.fallback),
      subtitle: Text(appLocalizations.fallbackDesc),
      delegate: OpenDelegate(
        blur: false,
        title: appLocalizations.fallback,
        widget: Consumer(builder: (_, ref, __) {
          final fallback = ref.watch(
            patchClashConfigProvider.select((state) => state.dns.fallback),
          );
          return ListInputPage(
            title: appLocalizations.fallback,
            items: fallback,
            titleBuilder: (item) => Text(item),
            onChange: (items) {
              ref.read(patchClashConfigProvider.notifier).updateState(
                    (state) => state.copyWith.dns(
                      fallback: List.from(items),
                    ),
                  );
            },
          );
        }),
      ),
    );
  }
}

class GeoipItem extends ConsumerWidget {
  const GeoipItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final geoip = ref.watch(
      patchClashConfigProvider
          .select((state) => state.dns.fallbackFilter.geoip),
    );
    return ListItem.switchItem(
      title: const Text("Geoip"),
      delegate: SwitchDelegate(
        value: geoip,
        onChanged: (bool value) async {
          ref
              .read(patchClashConfigProvider.notifier)
              .updateState((state) => state.copyWith.dns.fallbackFilter(
                    geoip: value,
                  ));
        },
      ),
    );
  }
}

class GeoipCodeItem extends ConsumerWidget {
  const GeoipCodeItem({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final geoipCode = ref.watch(
      patchClashConfigProvider
          .select((state) => state.dns.fallbackFilter.geoipCode),
    );
    return ListItem.input(
      title: Text(appLocalizations.geoipCode),
      subtitle: Text(geoipCode),
      delegate: InputDelegate(
        title: appLocalizations.geoipCode,
        value: geoipCode,
        validator: (value) {
          if (value == null || value.isEmpty) {
            return appLocalizations.emptyTip(appLocalizations.geoipCode);
          }
          return null;
        },
        onChanged: (String? value) {
          if (value == null) {
            return;
          }
          ref.read(patchClashConfigProvider.notifier).updateState(
                (state) => state.copyWith.dns.fallbackFilter(
                  geoipCode: value,
                ),
              );
        },
      ),
    );
  }
}

class GeositeItem extends StatelessWidget {
  const GeositeItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: const Text("Geosite"),
      delegate: OpenDelegate(
        blur: false,
        title: "Geosite",
        widget: Consumer(builder: (_, ref, __) {
          final geosite = ref.watch(
            patchClashConfigProvider
                .select((state) => state.dns.fallbackFilter.geosite),
          );
          return ListInputPage(
            title: "Geosite",
            items: geosite,
            titleBuilder: (item) => Text(item),
            onChange: (items) {
              ref.read(patchClashConfigProvider.notifier).updateState(
                    (state) => state.copyWith.dns.fallbackFilter(
                      geosite: List.from(items),
                    ),
                  );
            },
          );
        }),
      ),
    );
  }
}

class IpcidrItem extends StatelessWidget {
  const IpcidrItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.ipcidr),
      delegate: OpenDelegate(
        blur: false,
        title: appLocalizations.ipcidr,
        widget: Consumer(builder: (_, ref, ___) {
          final ipcidr = ref.watch(
            patchClashConfigProvider
                .select((state) => state.dns.fallbackFilter.ipcidr),
          );
          return ListInputPage(
            title: appLocalizations.ipcidr,
            items: ipcidr,
            titleBuilder: (item) => Text(item),
            onChange: (items) {
              ref
                  .read(patchClashConfigProvider.notifier)
                  .updateState((state) => state.copyWith.dns.fallbackFilter(
                        ipcidr: List.from(items),
                      ));
            },
          );
        }),
      ),
    );
  }
}

class DomainItem extends StatelessWidget {
  const DomainItem({super.key});

  @override
  Widget build(BuildContext context) {
    return ListItem.open(
      title: Text(appLocalizations.domain),
      delegate: OpenDelegate(
        blur: false,
        title: appLocalizations.domain,
        widget: Consumer(builder: (_, ref, __) {
          final domain = ref.watch(
            patchClashConfigProvider
                .select((state) => state.dns.fallbackFilter.domain),
          );
          return ListInputPage(
            title: appLocalizations.domain,
            items: domain,
            titleBuilder: (item) => Text(item),
            onChange: (items) {
              ref.read(patchClashConfigProvider.notifier).updateState(
                    (state) => state.copyWith.dns.fallbackFilter(
                      domain: List.from(items),
                    ),
                  );
            },
          );
        }),
      ),
    );
  }
}

class DnsOptions extends StatelessWidget {
  const DnsOptions({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: generateSection(
        title: appLocalizations.options,
        items: [
          const StatusItem(),
          const ListenItem(),
          const UseHostsItem(),
          const UseSystemHostsItem(),
          const IPv6Item(),
          const RespectRulesItem(),
          const PreferH3Item(),
          const DnsModeItem(),
          const FakeIpRangeItem(),
          const FakeIpFilterItem(),
          const DefaultNameserverItem(),
          const NameserverPolicyItem(),
          const NameserverItem(),
          const FallbackItem(),
          const ProxyServerNameserverItem(),
        ],
      ),
    );
  }
}

class FallbackFilterOptions extends StatelessWidget {
  const FallbackFilterOptions({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: generateSection(
        title: appLocalizations.fallbackFilter,
        items: [
          const GeoipItem(),
          const GeoipCodeItem(),
          const GeositeItem(),
          const IpcidrItem(),
          const DomainItem(),
        ],
      ),
    );
  }
}

const dnsItems = <Widget>[
  OverrideItem(),
  DnsOptions(),
  FallbackFilterOptions(),
];

class DnsListView extends ConsumerWidget {
  const DnsListView({super.key});

  @override
  Widget build(BuildContext context, ref) {
    return generateListView(
      dnsItems,
    );
  }
}
