// ignore_for_file: inference_failure_on_instance_creation
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart';
import 'package:twonly/src/providers/connection.provider.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/views/settings/subscription/additional_users.view.dart';
import 'package:twonly/src/views/settings/subscription/checkout.view.dart';
import 'package:twonly/src/views/settings/subscription/manage_subscription.view.dart';
import 'package:twonly/src/views/settings/subscription/transaction.view.dart';
import 'package:twonly/src/views/settings/subscription/voucher.view.dart';

String localePrizing(BuildContext context, int cents) {
  final myLocale = Localizations.localeOf(context);
  final euros = cents / 100;

  if (euros == euros.toInt()) {
    return '${euros.toInt()}€';
  }

  return NumberFormat.currency(
    locale: myLocale.toString(),
    symbol: '€',
    decimalDigits: 2,
  ).format(cents / 100);
}

Future<Response_PlanBallance?> loadPlanBalance({bool useCache = true}) async {
  final ballance = await apiService.getPlanBallance();
  if (ballance != null) {
    await updateUserdata((u) {
      u.lastPlanBallance = ballance.writeToJson();
      return u;
    });
    return ballance;
  }
  final user = await getUser();
  if (user != null && user.lastPlanBallance != null && useCache) {
    try {
      return Response_PlanBallance.fromJson(
        user.lastPlanBallance!,
      );
    } catch (e) {
      Log.error('from json: $e');
    }
  }
  return ballance;
}

// ignore: constant_identifier_names
const int MONTHLY_PAYMENT_DAYS = 30;
// ignore: constant_identifier_names
const int YEARLY_PAYMENT_DAYS = 365;

int calculateRefund(Response_PlanBallance current) {
  var refund = getPlanPrice('Pro', paidMonthly: true);

  if (current.paymentPeriodDays == YEARLY_PAYMENT_DAYS) {
    final elapsedDays = DateTime.now()
        .difference(DateTime.fromMillisecondsSinceEpoch(
            current.lastPaymentDoneUnixTimestamp.toInt() * 1000))
        .inDays;
    if (elapsedDays < current.paymentPeriodDays.toInt()) {
      // User has yearly plan with 10€
      // used it half a year and wants now to upgrade => gets 5€ discount...
      // math.ceil(((365-(365/2))/365)*10)
      // => 5€

      refund = (((YEARLY_PAYMENT_DAYS - elapsedDays) / YEARLY_PAYMENT_DAYS) *
                  getPlanPrice('Pro', paidMonthly: false) /
                  100)
              .ceil() *
          100;
    }
  } else {
    final elapsedDays = DateTime.now()
        .difference(DateTime.fromMillisecondsSinceEpoch(
            current.lastPaymentDoneUnixTimestamp.toInt() * 1000))
        .inDays;
    if (elapsedDays > 14) {
      refund = 0;
    }
  }
  return refund;
}

class SubscriptionView extends StatefulWidget {
  const SubscriptionView({super.key, this.redirectError});

  final ErrorCode? redirectError;

  @override
  State<SubscriptionView> createState() => _SubscriptionViewState();
}

class _SubscriptionViewState extends State<SubscriptionView> {
  bool loaded = false;
  bool testerRequested = true;
  Response_PlanBallance? ballance;
  String? additionalOwnerName;

  @override
  void initState() {
    super.initState();
    initAsync();
  }

  Future<void> initAsync() async {
    ballance = await loadPlanBalance();
    if (ballance != null && ballance!.hasAdditionalAccountOwnerId()) {
      final ownerId = ballance!.additionalAccountOwnerId.toInt();
      final contact = await twonlyDB.contactsDao
          .getContactByUserId(ownerId)
          .getSingleOrNull();
      if (contact != null) {
        additionalOwnerName = getContactDisplayName(contact);
      } else {
        additionalOwnerName = ownerId.toString();
      }
    }
    final user = await getUser();
    if (user != null) {
      testerRequested = user.requestedTesterAccount;
      // if (kDebugMode) {
      //   testerRequested = false;
      // }
    }
    setState(() {});
  }

  Future<void> _submitTesterRequest() async {
    final user = await getUser();
    if (user == null) return;
    final response = await http.post(
      Uri.parse('https://twonly.theconnectapp.de/subscribe.twonly.php'),
      headers: <String, String>{
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: {
        'feedback': '[TESTER REQUEST] ${user.username} ${user.userId}',
      },
    );
    if (!mounted) return;
    if (response.statusCode == 200) {
      // Handle successful response
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Your request has been submitted.')),
      );
      await updateUserdata((u) {
        u.requestedTesterAccount = true;
        return u;
      });
      await initAsync();
    } else {
      // Handle error response
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Failed to submit your request.')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    final myLocale = Localizations.localeOf(context);
    String? formattedBalance;
    DateTime? nextPayment;
    final currentPlan = context.read<CustomChangeProvider>().plan;
    final isAdditionalUser = currentPlan == 'Free' || currentPlan == 'Plus';

    if (ballance != null) {
      final lastPaymentDateTime = DateTime.fromMillisecondsSinceEpoch(
          ballance!.lastPaymentDoneUnixTimestamp.toInt() * 1000);
      if (!isAdditionalUser) {
        nextPayment = lastPaymentDateTime
            .add(Duration(days: ballance!.paymentPeriodDays.toInt()));
      }
      final ballanceInCents =
          ballance!.transactions.map((a) => a.depositCents.toInt()).sum;
      formattedBalance = NumberFormat.currency(
        locale: myLocale.toString(),
        symbol: '€',
        decimalDigits: 2,
      ).format(ballanceInCents / 100);
    }

    var refund = 0;
    if (currentPlan == 'Pro' && ballance != null) {
      refund = calculateRefund(ballance!);
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(context.lang.settingsSubscription),
      ),
      body: ListView(
        children: [
          if (widget.redirectError != null)
            Center(
              child: Container(
                padding: const EdgeInsets.all(16),
                margin: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: Colors.orangeAccent,
                  borderRadius: BorderRadius.circular(15),
                ),
                child: Text(
                  (widget.redirectError == ErrorCode.PlanLimitReached)
                      ? context.lang.planLimitReached
                      : context.lang.planNotAllowed,
                  style: const TextStyle(color: Colors.black),
                  textAlign: TextAlign.center,
                ),
              ),
            ),
          Padding(
            padding: const EdgeInsets.all(32),
            child: Center(
              child: Container(
                decoration: BoxDecoration(
                  color: context.color.primary,
                  borderRadius: BorderRadius.circular(15),
                ),
                padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
                child: Text(
                  currentPlan,
                  style: TextStyle(
                    fontSize: 32,
                    fontWeight: FontWeight.bold,
                    color: isDarkMode(context) ? Colors.black : Colors.white,
                  ),
                ),
              ),
            ),
          ),
          if (additionalOwnerName != null)
            Center(
              child: Text(
                context.lang.partOfPaidPlanOf(additionalOwnerName!),
                textAlign: TextAlign.center,
                style: const TextStyle(color: Colors.orange),
              ),
            ),
          if (currentPlan != 'Family' && currentPlan != 'Pro')
            Center(
              child: Padding(
                padding: const EdgeInsets.all(18),
                child: Text(
                  context.lang.upgradeToPaidPlan,
                  textAlign: TextAlign.center,
                  style: const TextStyle(fontSize: 18),
                ),
              ),
            ),
          if (currentPlan != 'Tester' && !testerRequested)
            PlanCard(
              planId: 'Tester',
              onTap: () async {
                final activate = await showAlertDialog(
                  context,
                  context.lang.testingAccountTitle,
                  context.lang.testingAccountBody,
                );
                if (activate) {
                  await _submitTesterRequest();
                }
              },
            ),
          if (currentPlan != 'Family' && currentPlan != 'Pro')
            PlanCard(
              planId: 'Pro',
              onTap: () async {
                await Navigator.push(context,
                    MaterialPageRoute(builder: (context) {
                  return const CheckoutView(
                    planId: 'Pro',
                  );
                }));
                await initAsync();
              },
            ),
          if (currentPlan != 'Family')
            PlanCard(
              planId: 'Family',
              refund: refund,
              onTap: () async {
                await Navigator.push(context,
                    MaterialPageRoute(builder: (context) {
                  return CheckoutView(
                    planId: 'Family',
                    refund: (refund > 0) ? refund : null,
                    disableMonthlyOption: currentPlan == 'Pro' &&
                        ballance!.paymentPeriodDays.toInt() ==
                            YEARLY_PAYMENT_DAYS,
                  );
                }));
                await initAsync();
              },
            ),
          if (currentPlan == 'Preview' || currentPlan == 'Free') ...[
            const SizedBox(height: 10),
            Center(
              child: Padding(
                padding: const EdgeInsets.all(14),
                child: Text(
                  context.lang.redeemUserInviteCode,
                  textAlign: TextAlign.center,
                  style: const TextStyle(fontSize: 18),
                ),
              ),
            ),
            const SizedBox(height: 10),
            if (currentPlan != 'Free')
              PlanCard(
                planId: 'Free',
                onTap: () async {
                  await redeemUserInviteCode(context, 'Free');
                  await initAsync();
                },
              ),
            PlanCard(
              planId: 'Plus',
              onTap: () async {
                await redeemUserInviteCode(context, 'Plus');
                await initAsync();
              },
            ),
          ],
          const SizedBox(height: 10),
          if (currentPlan != 'Family') const Divider(),
          if (currentPlan != 'Preview')
            BetterListTile(
              icon: FontAwesomeIcons.gears,
              text: context.lang.manageSubscription,
              subtitle: (nextPayment != null)
                  ? Text(
                      '${context.lang.nextPayment}: ${DateFormat.yMMMMd(myLocale.toString()).format(nextPayment)}')
                  : null,
              onTap: () async {
                await Navigator.push(context,
                    MaterialPageRoute(builder: (context) {
                  return ManageSubscriptionView(
                    ballance: ballance,
                    nextPayment: nextPayment,
                  );
                }));
                await initAsync();
              },
            ),
          BetterListTile(
            icon: FontAwesomeIcons.moneyBillTransfer,
            text: context.lang.transactionHistory,
            subtitle: (formattedBalance != null)
                ? Text('${context.lang.currentBalance}: $formattedBalance')
                : null,
            onTap: () {
              if (formattedBalance == null) return;
              Navigator.push(context, MaterialPageRoute(builder: (context) {
                return TransactionView(
                  transactions: ballance?.transactions,
                  formattedBalance: formattedBalance!,
                );
              }));
            },
          ),
          if (!isAdditionalUser)
            BetterListTile(
              icon: FontAwesomeIcons.userPlus,
              text: context.lang.manageAdditionalUsers,
              subtitle: loaded ? Text('${context.lang.open}: 3') : null,
              onTap: () async {
                await Navigator.push(context,
                    MaterialPageRoute(builder: (context) {
                  return AdditionalUsersView(
                    ballance: ballance,
                  );
                }));
                await initAsync();
              },
            ),
          BetterListTile(
            icon: FontAwesomeIcons.ticket,
            text: context.lang.createOrRedeemVoucher,
            onTap: () async {
              await Navigator.push(context,
                  MaterialPageRoute(builder: (context) {
                return const VoucherView();
              }));
              await initAsync();
            },
          ),
          const SizedBox(height: 30)
        ],
      ),
    );
  }
}

int getPlanPrice(String planId, {required bool paidMonthly}) {
  switch (planId) {
    case 'Pro':
      return paidMonthly ? 100 : 1000;
    case 'Family':
      return paidMonthly ? 200 : 2000;
  }
  return 0;
}

class PlanCard extends StatelessWidget {
  const PlanCard({
    required this.planId,
    super.key,
    this.refund,
    this.onTap,
    this.paidMonthly,
  });
  final String planId;
  final void Function()? onTap;
  final int? refund;
  final bool? paidMonthly;

  @override
  Widget build(BuildContext context) {
    final yearlyPrice = getPlanPrice(planId, paidMonthly: false);
    final monthlyPrice = getPlanPrice(planId, paidMonthly: true);
    var features = <String>[];

    switch (planId) {
      case 'Free':
        features = [context.lang.freeFeature1];
      case 'Plus':
        features = [context.lang.plusFeature1];
      case 'Tester':
      case 'Pro':
        features = [
          context.lang.proFeature1,
          context.lang.proFeature2,
          context.lang.proFeature3
        ];
      case 'Family':
        features = [
          context.lang.familyFeature1,
          context.lang.familyFeature2,
          context.lang.familyFeature3
        ];
      default:
    }

    return Padding(
      padding: const EdgeInsets.only(left: 16, right: 16),
      child: GestureDetector(
        onTap: onTap,
        child: Card(
          elevation: 4,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10),
          ),
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
            child: Column(
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Text(
                      planId,
                      textAlign: TextAlign.center,
                      style: const TextStyle(
                        fontSize: 24,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    if (yearlyPrice != 0) const SizedBox(height: 10),
                    if (yearlyPrice != 0 && paidMonthly == null)
                      Column(
                        children: [
                          if (paidMonthly == null || paidMonthly!)
                            Text(
                              '${localePrizing(context, yearlyPrice)}/${context.lang.year}',
                              textAlign: TextAlign.center,
                              style: const TextStyle(
                                fontSize: 20,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          if (paidMonthly == null || !paidMonthly!)
                            Text(
                              '${localePrizing(context, monthlyPrice)}/${context.lang.month}',
                              textAlign: TextAlign.center,
                              style: const TextStyle(
                                fontSize: 16,
                                color: Colors.grey,
                              ),
                            ),
                        ],
                      ),
                    if (paidMonthly != null)
                      Text(
                        (paidMonthly!)
                            ? '${localePrizing(context, monthlyPrice)}/${context.lang.month}'
                            : '${localePrizing(context, yearlyPrice)}/${context.lang.year}',
                        textAlign: TextAlign.center,
                        style: const TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                  ],
                ),
                const SizedBox(height: 10),
                ...features.map(
                  (feature) => Padding(
                    padding: const EdgeInsets.symmetric(vertical: 2),
                    child: Text(
                      feature,
                      textAlign: TextAlign.center,
                    ),
                  ),
                ),
                if (refund != null && refund! > 0)
                  Padding(
                    padding: const EdgeInsets.only(top: 7),
                    child: Text(
                      context.lang
                          .subscriptionRefund(localePrizing(context, refund!)),
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        color: context.color.primary,
                        fontSize: 12,
                      ),
                    ),
                  ),
                if (onTap != null)
                  Padding(
                    padding: const EdgeInsets.only(top: 10),
                    child: FilledButton.icon(
                      onPressed: onTap,
                      label: (planId == 'Free' || planId == 'Plus')
                          ? Text(context.lang.redeemUserInviteCodeTitle)
                          : Text(context.lang.upgradeToPaidPlanButton(planId)),
                    ),
                  )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Future<void> redeemUserInviteCode(BuildContext context, String newPlan) async {
  var inviteCode = '';
  // ignore: inference_failure_on_function_invocation
  await showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text(context.lang.redeemUserInviteCodeTitle),
        content: StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            return SingleChildScrollView(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Padding(
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    child: TextField(
                      onChanged: (value) => setState(() {
                        inviteCode = value.toUpperCase();
                      }),
                      decoration: InputDecoration(
                        labelText: context.lang.registerTwonlyCodeLabel,
                        border: const OutlineInputBorder(),
                      ),
                      textCapitalization: TextCapitalization.characters,
                    ),
                  ),
                ],
              ),
            );
          },
        ),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop();
            },
            child: Text(context.lang.cancel),
          ),
          TextButton(
            onPressed: () async {
              final res = await apiService.redeemUserInviteCode(inviteCode);
              if (!context.mounted) return;
              if (res.isSuccess) {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text(context.lang.redeemUserInviteCodeSuccess),
                  ),
                );
                // reconnect to load new plan.
                await apiService.close(() {});
                await apiService.connect(force: true);
              } else {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                      content: Text(
                          errorCodeToText(context, res.error as ErrorCode))),
                );
              }
              if (!context.mounted) return;
              Navigator.of(context).pop();
            },
            child: Text(context.lang.ok),
          ),
        ],
      );
    },
  );
}
