import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import '/components/flash_message.dart';
import '/database/models/my_profile.dart';
import '/utils/encryption/aes_helper.dart';
import '/utils/encryption/crypto_utils.dart';


class Signup extends StatelessWidget {
  const Signup({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: null,
          automaticallyImplyLeading: true,
          //`true` if you want Flutter to automatically add Back Button when needed,
          //or `false` if you want to force your own back button every where
          leading: IconButton(icon: const Icon(Icons.arrow_back),
              onPressed:() => {
                Navigator.pop(context)
              }
          ),
          backgroundColor: Colors.transparent,
          shadowColor: Colors.transparent,
        ),
        body: const SafeArea(
            child: SignupWidget(),
        )
    );
  }
}

class SignupResponse {
  final String status;
  final String message;

  const SignupResponse({
    required this.status,
    required this.message,
  });

  factory SignupResponse.fromJson(Map<String, dynamic> json) {
    return SignupResponse(
      status: json['status'],
      message: json['message'],
    );
  }
}

class SignupWidget extends StatefulWidget {
  const SignupWidget({Key? key}) : super(key: key);

  @override
  State<SignupWidget> createState() => _SignupWidgetState();
}

class _SignupWidgetState extends State<SignupWidget> {
  final _formKey = GlobalKey<FormState>();

  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final TextEditingController _passwordConfirmController = TextEditingController();
  final TextEditingController _serverUrlController = TextEditingController();

  bool showUrlInput = false;

  final OutlineInputBorder inputBorderStyle = OutlineInputBorder(
      borderRadius: BorderRadius.circular(5),
      borderSide: const BorderSide(
          color: Colors.transparent,
      )
  );

  final TextStyle inputTextStyle = const TextStyle(
      fontSize: 18,
  );

  @override
  Widget build(BuildContext context) {

    final ButtonStyle buttonStyle = ElevatedButton.styleFrom(
      backgroundColor: Theme.of(context).colorScheme.tertiary,
      minimumSize: const Size.fromHeight(50),
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
      textStyle: TextStyle(
        fontSize: 20,
        fontWeight: FontWeight.bold,
        color: Theme.of(context).colorScheme.error,
      ),
    );

    return Center(
      child: SingleChildScrollView(
        child: Form(
          key: _formKey,
          child: Center(
            child: Padding(
              padding: const EdgeInsets.only(
                  left: 20,
                  right: 20,
                  top: 0,
                  bottom: 100,
              ),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Text(
                    'Sign Up',
                    style: TextStyle(
                      fontSize: 35,
                      color: Theme.of(context).colorScheme.onBackground,
                    ),
                  ),
                  const SizedBox(height: 30),
                  input(
                    _usernameController,
                    'Username',
                    false,
                    (value) {
                      if (value == null || value.isEmpty) {
                        return 'Create a username';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 10),
                  input(
                    _passwordController,
                    'Password',
                    true,
                    (value) {
                      if (value == null || value.isEmpty) {
                        return 'Enter a password';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 10),
                  input(
                    _passwordConfirmController,
                    'Confirm Password',
                    true,
                    (value) {
                      if (value == null || value.isEmpty) {
                        return 'Confirm your password';
                      }
                      if (value != _passwordController.text) {
                        return 'Passwords do not match';
                      }
                      return null;
                    },
                  ),
                  const SizedBox(height: 15),
                  serverUrl(),
                  const SizedBox(height: 15),
                  ElevatedButton(
                    style: buttonStyle,
                    onPressed: () {
                      if (!_formKey.currentState!.validate()) {
                        return;
                      }

                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text('Processing Data')),
                      );

                      signUp()
                        .then((dynamic) {
                          Navigator.of(context).popUntil((route) => route.isFirst);
                        }).catchError((error) {
                          showMessage('Failed to signup to Envelope, please try again later', context);
                        });
                    },
                    child: const Text('Submit'),
                  ),
                ],
              )
            )
          )
        )
      )
    );
  }

  Widget input(
    TextEditingController textController,
    String hintText,
    bool password,
    String? Function(dynamic) validationFunction,
  ) {
    return TextFormField(
      controller: textController,
      obscureText: password,
      enableSuggestions: false,
      autocorrect: false,
      decoration: InputDecoration(
        hintText: hintText,
        enabledBorder: inputBorderStyle,
        focusedBorder: inputBorderStyle,
      ),
      style: inputTextStyle,
      validator: validationFunction,
    );
  }

  Widget serverUrl() {
    if (!showUrlInput) {
      return
          Padding(
          padding: const EdgeInsets.only(top: 0, bottom: 10),
          child: Row(
            children: [
              SizedBox(
                height: 10,
                child: IconButton(
                  onPressed: () {
                    setState(() {
                      showUrlInput = true;
                    });
                  },
                  icon: Icon(
                    Icons.edit,
                    color: Theme.of(context).disabledColor,
                  ),
                  splashRadius: 2,
                  padding: const EdgeInsets.all(2),
                  iconSize: 15,
                ),
              ),
              const SizedBox(width: 2),
              Column(
                children: [
                  const SizedBox(height: 10),
                  Text(
                    'Server URL - $defaultServerUrl',
                    style: TextStyle(
                      color: Theme.of(context).disabledColor,
                      fontSize: 12,
                    ),
                  ),
                ],
              ),
            ],
        ),
      );
    }

    if (_serverUrlController.text == '') {
      _serverUrlController.text = defaultServerUrl;
    }

    return input(
      _serverUrlController,
      'Server URL',
      false,
      (dynamic) {
        return null;
      },
    );
  }

  Future<SignupResponse> signUp() async {
    await MyProfile.setServerUrl(_serverUrlController.text);

    var keyPair = CryptoUtils.generateRSAKeyPair();

    var rsaPubPem = CryptoUtils.encodeRSAPublicKeyToPem(keyPair.publicKey);
    var rsaPrivPem = CryptoUtils.encodeRSAPrivateKeyToPem(keyPair.privateKey);

    String encRsaPriv = AesHelper.aesEncrypt(
      _passwordController.text,
      Uint8List.fromList(rsaPrivPem.codeUnits),
    );

    final resp = await http.post(
      await MyProfile.getServerUrl('api/v1/signup'),
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        'username': _usernameController.text,
        'password': _passwordController.text,
        'confirm_password': _passwordConfirmController.text,
        'asymmetric_public_key': rsaPubPem,
        'asymmetric_private_key': encRsaPriv,
      }),
    );

    SignupResponse response = SignupResponse.fromJson(jsonDecode(resp.body));

    if (resp.statusCode != 201) {
      throw Exception(response.message);
    }

    return response;
  }
}