package zero1hd.rhythmbullet.desktop.screens.main;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.ButtonGroup;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Array;

import zero1hd.rhythmbullet.desktop.Controls;
import zero1hd.rhythmbullet.graphics.ui.Page;

public class KeybindPage extends Page {
	private ButtonGroup<KeyChangeButton> buttonOptions;
	private VerticalGroup group;
	private ScrollPane scrollPane;
	private Skin skin;
	TextureAtlas keyTextures;
	private Preferences keyBindPrefs;
	private InputListener inputListener;
	private ChangeListener checkedListener;
	
	public KeybindPage(AssetManager assetManager, Skin skin, ChangeListener backButtonListener) {
		super(-1, -1);
		setTouchable(Touchable.enabled);
		this.skin = skin;
		keyTextures = assetManager.get("keyboard.atlas", TextureAtlas.class);
		this.keyBindPrefs = Gdx.app.getPreferences("PolyJet_Controls");		
		TextButton backButton = new TextButton("Back", skin);
		backButton.setWidth(backButton.getWidth()+20f);
		backButton.setPosition(getWidth()-backButton.getWidth()-15f, getHeight() - backButton.getHeight() - 15f);
		backButton.addListener(backButtonListener);
		addActor(backButton);
		
		inputListener = new InputListener() {
			@Override
			public boolean keyUp(InputEvent event, int keycode) {
				KeyChangeButton button = buttonOptions.getChecked();
				if (button != null) {
					if (keycode != Keys.ESCAPE) {
						button.attemptSetKeycode(keycode);
					}
					getStage().setKeyboardFocus(null);
				}
				return super.keyUp(event, keycode);
			}
		};
		
		checkedListener = new ChangeListener() {
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				KeyChangeButton button = (KeyChangeButton) actor;
				if (button.isChecked()) {
					button.ready();
				} else {
					button.done();
				}
			}
		};
		
		buttonOptions = new ButtonGroup<>();
		buttonOptions.setMinCheckCount(0);
		buttonOptions.setMaxCheckCount(1);
		group = new VerticalGroup();
		group.setTouchable(Touchable.childrenOnly);
		group.space(15f);
		Controls[] controls = Controls.values();
		for (int i = 0; i < controls.length; i++) {
			KeyChangeButton button = new KeyChangeButton(controls[i]);
			buttonOptions.add(button);
			group.addActor(button);
		}
		scrollPane = new ScrollPane(group);
		scrollPane.setHeight(Math.min(getHeight(), group.getPrefHeight()));
		scrollPane.setWidth(group.getPrefWidth());
		scrollPane.setPosition((getWidth()-scrollPane.getWidth())/2f, (getHeight()-scrollPane.getHeight())/2f);
		scrollPane.setTouchable(Touchable.childrenOnly);
		addActor(scrollPane);
		addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				if (hit(x, y, true) == event.getListenerActor()) {
					simpleDebug("unchecking selected key change buttons.");
					buttonOptions.uncheckAll();
				}
				super.clicked(event, x, y);
			}
		});
	}
	
	@Override
	public void setCameraPositionToPage(Vector3 cameraPosition) {
		getStage().setScrollFocus(scrollPane);
		super.setCameraPositionToPage(cameraPosition);
	}
	
	@Override
	public void dispose() {
		save();
		super.dispose();
	}
	public void save() {
		keyBindPrefs.flush();
	}
	
	public class KeyChangeButton extends Button {
		private Image keyImage;
		private Label nameLabel;
		private Controls control;
		private boolean error;
		
		public KeyChangeButton(Controls control) {
			super(skin, "selectable-clean-button");
			this.control = control;
			nameLabel = new Label(control.toString(), skin);
			keyImage = new Image(getIcon(control.getKeycode()));
			
			add(nameLabel).expandX().left().spaceRight(20f);
			add(keyImage).expandX().right();
			
			addListener(inputListener);
			addListener(checkedListener);
		}
		
		public void attemptSetKeycode(int keycode) {
			simpleDebug("Attempting to set keycode to " + keycode);
			TextureRegion textureRegion = getIcon(keycode);
			if (textureRegion != null) {
				setKeycode(keycode, textureRegion);
				error = false;
			} else {
				error = true;
			}
			setChecked(false);
		}
		
		public void setKeycode(int keycode, TextureRegion texture) {
			
			Controls conflict = control.setKeycode(keycode);
			if (conflict != null) {
				Array<KeyChangeButton> buttons = buttonOptions.getButtons();
				for (int i = 0; i < buttons.size; i++) {
					System.out.println(buttons.get(i).getControl());
					if (buttons.get(i).getControl() == conflict) {
						KeyChangeButton b = buttons.get(i);
						scrollPane.scrollTo(b.getX(), b.getY(), b.getWidth(), b.getHeight());
						b.done(true);
						return;
					}
				}
			} 
			TextureRegion textureRegion = getIcon(keycode);
			if (textureRegion != null) {
				keyImage.setDrawable(new TextureRegionDrawable(texture));
				control.saveKeyToPreferences(keyBindPrefs);
			}
		}
		
		public void ready() {
			getStage().setKeyboardFocus(this);
			keyImage.setColor(Color.ORANGE);
		}
		
		public void done() {
			done(error);
		}
		
		public void done(boolean error) {
			if (error) {
				keyImage.addAction(Actions.repeat(3, Actions.sequence(Actions.color(Color.RED, 0.2f), Actions.color(Color.WHITE, 0.1f))));
			} else {
				keyImage.addAction(Actions.color(Color.WHITE, 0.2f));
			}
		}
		
		public Controls getControl() {
			return control;
		}
	}
	
	public TextureRegion getIcon(int keycode) {
		switch (keycode) {
		case Keys.ALT_LEFT:
		case Keys.ALT_RIGHT:
			return keyTextures.findRegion("Keyboard_Black_Alt");
		case Keys.SHIFT_LEFT:
		case Keys.SHIFT_RIGHT:
			return keyTextures.findRegion("Keyboard_Black_Shift");
		case Keys.LEFT_BRACKET:
			return keyTextures.findRegion("Keyboard_Black_Bracket_Left");
		case Keys.RIGHT_BRACKET:
			return keyTextures.findRegion("Keyboard_Black_Bracket_Right");
		case Keys.SEMICOLON:
			return keyTextures.findRegion("Keyboard_Black_Semicolon");
		case Keys.SLASH:
			return keyTextures.findRegion("Keyboard_Black_Slash");
		case Keys.NUM:
			return keyTextures.findRegion("Keyboard_Black_Num_Lock");
		case Keys.ESCAPE:
			return null;
		default:
			return keyTextures.findRegion("Keyboard_Black_" + Keys.toString(keycode).replace(' ', '_'));
		}
	}
}
