package xyz.thastertyn.Login;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Optional;
import java.util.concurrent.TimeoutException;

import javax.naming.ConfigurationException;
import javax.security.auth.login.CredentialException;

import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
import com.googlecode.lanterna.gui2.dialogs.MessageDialog;
import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton;

import xyz.thastertyn.Config.Config;
import xyz.thastertyn.Scrape.Downloader;
import xyz.thastertyn.Types.Credentials;
import xyz.thastertyn.Types.InputtedCredentials;

/**
 * Merges the functionality of {@link Config}, {@link CredentialsInput}, and {@link Login}
 */
public class LoginController {
	
	private WindowBasedTextGUI textGUI;
	private xyz.thastertyn.Login.CredentialsInput dialog;
	private Config config = Config.getInstance();
	private xyz.thastertyn.Login.Login login = new xyz.thastertyn.Login.Login();

	public LoginController(WindowBasedTextGUI textGUI)
	{
		this.textGUI = textGUI;
	}

	/**
	 * Picks appropriate method for logging in
	 * <ul>
	 * <li> Locally stored credentials exist, then try using them. If they arent in good shape, use GUI
	 * <li> Use GUI and ask the user for credentials
	 * </ul>
	*/
	public void login(boolean forceGUI)
	{
		if(forceGUI || !config.checkIfCredentialsExist())
		{
			Optional<Credentials> optional = loginUsingGui();

			if(optional.isEmpty())
			{
				if(!Downloader.isInitialized())
				{
					System.exit(0);
				}

				return;
			}

			useCredentials(optional.get());
		}else{
			try{
				useCredentials(config.getCredentials());
			}catch(ConfigurationException e) {
				e.printStackTrace();
				login(true);
			}
		}
	}

	public Optional<Credentials> loginUsingGui()
	{
		dialog = new CredentialsInput();

		Optional<InputtedCredentials> credentialsOptional = dialog.showDialog(textGUI);

		if(credentialsOptional.isEmpty())
		{
			if(!Downloader.isInitialized())
			{
				System.exit(0);
			}
			return Optional.empty();
		}

		InputtedCredentials inputtedCredentials = credentialsOptional.get();

		if(inputtedCredentials.save())
		{
			config.addConfig("user", inputtedCredentials.getUsername());
			config.addConfig("pass", inputtedCredentials.getPassword());
			
			if(!config.writeConfig())
			{
				MessageDialog.showMessageDialog(textGUI, "Failed to save credentials", "Something has gone wrong while saving your credentials", MessageDialogButton.OK);
			}
		}

		return Optional.of(inputtedCredentials.getCredentials());
	}

	/**
	 * Credentials were successfully obtained and are used for logging in, although a lot can go wrong
	 * @param credentials
	 */
	private void useCredentials(Credentials credentials)
	{
		try {
			login.loginJecna(credentials);
		}catch (TimeoutException e)
		{
			MessageDialog.showMessageDialog(textGUI, "Timeout", "The attempt to connect took too long. The app will quit", MessageDialogButton.OK);
			System.exit(0);
		} catch (UnknownHostException e) {
			MessageDialog.showMessageDialog(textGUI, "No Internet connection. The app will quit",
					e.getMessage(), 
					MessageDialogButton.OK);
			System.exit(0);
		} catch (CredentialException e)
		{
			MessageDialog.showMessageDialog(textGUI, "Incorrect username or password", 
			e.getMessage(), 
			MessageDialogButton.OK);
			// The credentials were most likely tampered with after save, just get rid of them and save them another time
			Config.getInstance()
				.removeCredentials()
				.writeConfig();
			login(true);
		} catch (IOException e)
		{
			MessageDialog.showMessageDialog(textGUI, "There was an error. The app will quit", 
			e.getMessage(), 
			MessageDialogButton.Retry);
			System.exit(0);
		}
	}
}
