import 'package:finnow_app/api/auth.dart';
import 'package:finnow_app/auth/model.dart';
import 'package:finnow_app/components/form_label.dart';
import 'package:finnow_app/components/title_text.dart';
import 'package:finnow_app/main.dart';
import 'package:finnow_app/util/debouncer.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

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

  @override
  Widget build(BuildContext context) {
    return Material(
        child: Center(
            child: Container(
                constraints: const BoxConstraints(maxWidth: 300.0),
                padding: const EdgeInsets.all(10),
                child: const RegisterForm())));
  }
}

class RegisterForm extends StatefulWidget {
  const RegisterForm({super.key});

  @override
  State<RegisterForm> createState() => _RegisterFormState();
}

class _RegisterFormState extends State<RegisterForm> {
  final formKey = GlobalKey<FormState>();
  final usernameTextController = TextEditingController();
  final passwordTextController = TextEditingController();
  var loading = false;
  final usernameAvailabilityDebouncer = Debouncer();
  bool? usernameAvailable;
  var canCreateAccount = false;

  @override
  Widget build(BuildContext context) {
    return Form(
        key: formKey,
        child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
          const TitleText('Create a Finnow Account'),
          const SizedBox(height: 20),
          const FormLabel('Username'),
          TextFormField(
            controller: usernameTextController,
            onChanged: (s) {
              formValuesUpdated();
              usernameAvailabilityDebouncer
                  .run(() => checkUsernameAvailability());
            },
            decoration: const InputDecoration(
                hintText: 'Enter username', border: OutlineInputBorder()),
            validator: usernameValidator,
          ),
          if (usernameAvailable != null && usernameAvailable == true) ...[
            const Text('Username is available.',
                style: TextStyle(color: Colors.green))
          ],
          if (usernameAvailable != null && usernameAvailable == false) ...[
            const Text('Username is taken.',
                style: TextStyle(color: Colors.red))
          ],
          const SizedBox(
            height: 10,
          ),
          const FormLabel('Password'),
          TextFormField(
              controller: passwordTextController,
              onChanged: (s) => formValuesUpdated(),
              obscureText: true,
              decoration: const InputDecoration(
                  hintText: 'Enter password', border: OutlineInputBorder()),
              validator: passwordValidator),
          const SizedBox(height: 10),
          TextButton(
            onPressed: loading || !canCreateAccount ? null : createAccount,
            child: const Text('Create Account'),
          ),
          const SizedBox(
            height: 10,
          ),
          TextButton(
              onPressed: () {
                getIt<GoRouter>().replace('/login');
              },
              child: const Text('Back to Login'))
        ]));
  }

  @override
  void dispose() {
    usernameTextController.dispose();
    passwordTextController.dispose();
    super.dispose();
  }

  void formValuesUpdated() {
    final usernameValidation = usernameValidator(usernameTextController.text);
    final passwordValidation = passwordValidator(passwordTextController.text);
    setState(() {
      canCreateAccount =
          usernameValidation == null && passwordValidation == null;
    });
  }

  void checkUsernameAvailability() async {
    final usernameText = usernameTextController.text;
    // Set usernameAvailable to null if the username is invalid.
    if (usernameValidator(usernameText) != null) {
      setState(() => usernameAvailable = null);
      return;
    }
    // Otherwise, there's a valid username, so check if it's available.
    final available = await getUsernameAvailability(usernameText);
    setState(() => usernameAvailable = available);
  }

  void createAccount() async {
    print('Creating account...');
    if (formKey.currentState!.validate()) {
      setState(() => loading = true);
      final credentials = LoginCredentials(
          usernameTextController.text, passwordTextController.text);
      try {
        final token = await postRegister(credentials);
        getIt<AuthenticationModel>().state =
            Authenticated(token, credentials.username);
      } catch (e) {
        print(e);
      } finally {
        setState(() => loading = false);
      }
    }
  }
}
