using Cryville.Common.Pdt;
using UnityEngine;

namespace Cryville.Crtr.Components {
	public abstract class SpriteBase : SkinComponent {
		public SpriteBase() {
			SubmitProperty("bound", new op_set_bound(this));
			SubmitProperty("transparent", new PropOp.Boolean(v => transparent = v));
			SubmitProperty("pivot", new PropOp.Vector2(v => Pivot = v));
			SubmitProperty("scale", new PropOp.Vector2(v => Scale = v));
			SubmitProperty("ui", new PropOp.Boolean(v => UI = v));
			SubmitProperty("zindex", new PropOp.Integer(v => ZIndex = (short)v));
		}

#pragma warning disable IDE1006
		class op_set_bound : PdtOperator {
			readonly SpriteBase _self;
			public op_set_bound(SpriteBase self) : base(2) {
				_self = self;
			}
			protected unsafe override void Execute() {
				_self.SetBound(
					*(Vector2*)GetOperand(0).TrustedAsOfLength(sizeof(Vector2)),
					*(Vector3*)GetOperand(1).TrustedAsOfLength(sizeof(Vector3))
				);
			}
		}
#pragma warning restore IDE1006

		protected MeshWrapper mesh = new MeshWrapper();

		protected override void OnDestroy() {
			mesh.Destroy();
		}

		Vector2 _scale = Vector2.one;
		public Vector2 Scale {
			get { return _scale; }
			set {
				_scale = value;
				UpdateScale();
			}
		}
		protected virtual void UpdateScale() {
			if (!mesh.Initialized) return;
			var s = BaseScale;
			var ss = new Vector3(_scale.x, 1, _scale.y);
			s.Scale(ss);
			mesh.MeshTransform.localScale = s;
			OnPivotUpdate();
		}
		protected abstract Vector3 BaseScale {
			get;
		}
		protected virtual Vector3 BaseSize {
			get { return Vector3.one; }
		}
		
		Vector2 _pivot;
		public Vector2 Pivot {
			get { return _pivot; }
			set {
				_pivot = value;
				OnPivotUpdate();
			}
		}
		protected void OnPivotUpdate() {
			if (!mesh.Initialized) return;
			var r = new Vector3(_pivot.x - BasePivot.x, 0, _pivot.y - BasePivot.y);
			r.Scale(mesh.MeshTransform.localScale);
			r.Scale(BaseSize);
			mesh.MeshTransform.localPosition = -r;
		}
		protected virtual Vector2 BasePivot {
			get { return Vector2.zero; }
		}

		public void SetBound(Vector2 piv, Vector3 pos) {
			var r = Quaternion.Inverse(transform.rotation);
			var da = piv - Pivot;
			var dp = r * (pos - transform.localPosition);
			if (da.x != 0) _scale.x = dp.x / da.x;
			if (da.y != 0) _scale.y = dp.z / da.y;
		}
		
		short _zindex;
		public short ZIndex {
			get {
				return _zindex;
			}
			set {
				_zindex = value;
				UpdateZIndex();
			}
		}
		protected void UpdateZIndex() {
			if (!mesh.Initialized) return;
			mesh.Renderer.sortingOrder = _zindex;
		}

		static readonly Quaternion uirot
			= Quaternion.Euler(new Vector3(-90, 0, 0));
		bool _ui;
		public bool UI {
			get { return _ui; }
			set {
				_ui = value;
				if (_ui) transform.localRotation = uirot;
			}
		}

		public bool transparent = false;

		protected void InternalInit(string meshName = "quad") {
			mesh.Init(transform, transparent);
			mesh.Mesh = GenericResources.Meshes[meshName];
			UpdateScale();
			UpdateZIndex();
		}
	}
}
