using Microsoft.AspNetCore.Mvc;
using backend.Application;
using backend.Models;
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Identity;
using System.Web;

namespace backend.Controllers;

[ApiController]
public class UserController : ControllerBase
{
	[HttpPost("Register")]
	public IActionResult Register([FromBody] JsonObject input)
	{
		// Validate
		if (String.IsNullOrEmpty(input["username"]?.ToString()) || String.IsNullOrEmpty(input["password"]?.ToString())) {
			return BadRequest("Username and password required");
		}

		if (ApplicationState.DbContext!.Users.FirstOrDefault(user => user.Username == input["username"]!.ToString()) != null) {
			return BadRequest("User already exists");
		}

		// Hash password
		var passwordHasher = new PasswordHasher<object>();
		string hashedPassword = passwordHasher.HashPassword(null, input["password"]!.ToString());

		// Generate touch code
		string touchCode = "";
		for (int i = 0; i < 4; i++) {
			touchCode += (1 + new Random().Next() % 5).ToString();
		}

		// Create user
		var user = new User {
			Username = input["username"]!.ToString(),
			Password = hashedPassword,
			TouchCode = touchCode,
		};

		// Save user
		ApplicationState.DbContext!.Add(user);
		ApplicationState.DbContext!.SaveChanges();

		Console.WriteLine("Created user: " + user.Username);

		return Ok();
	}

	[HttpPost("Login")]
	public IActionResult Login([FromBody] JsonObject input)
	{
		// Validate
		if (String.IsNullOrEmpty(input["username"]?.ToString()) || String.IsNullOrEmpty(input["password"]?.ToString())) {
			return BadRequest("Username and password required");
		}

		if (Request.Cookies["session"] != null) {
			return BadRequest("You are already logged in");
		}

		// Get user
		var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.Username == input["username"]!.ToString());
		if (user == null) {
			return BadRequest("Invalid username");
		}

		// Verify password
		var passwordHasher = new PasswordHasher<object>();
		if (passwordHasher.VerifyHashedPassword(null, user.Password, input["password"]!.ToString()) == PasswordVerificationResult.Failed) {
			return BadRequest("Invalid password");
		}

		// Create session token if necessary
		if (string.IsNullOrEmpty(user.SessionToken)) {
			user.SessionToken = Guid.NewGuid().ToString();
			ApplicationState.DbContext!.SaveChanges();
		}

		// Set session cookie
		Response.Cookies.Append("session", user.SessionToken);

		Console.WriteLine(user.Username + " has logged in");

		return Ok();
	}

	[HttpPost("Logout")]
	public IActionResult LogOut()
	{
		// Validate
		if (Request.Cookies["session"] == null) {
			return BadRequest("You are not logged in");
		}

		// Get user
		var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.SessionToken == Request.Cookies["session"]!.ToString());
		if (user == null) {
			return BadRequest("Invalid session token");
		}

		// Log out
		user.SessionToken = null;
		ApplicationState.DbContext!.SaveChanges();

		Response.Cookies.Delete("session");

		return Ok();
	}

	[HttpGet("UserInfo")]
	public IActionResult UserInfo()
	{
		// Validate
		if (Request.Cookies["session"] == null) {
			return BadRequest("You are not logged in");
		}

		// Get user
		var user = ApplicationState.DbContext!.Users.FirstOrDefault(user => user.SessionToken == Request.Cookies["session"]!.ToString());
		if (user == null) {
			return BadRequest("Invalid session token");
		}

		var data = new {
			username = user.Username,
			touchCode = user.TouchCode,
		};

		return new JsonResult(data);
	}
}
