using UnityEngine;

namespace QSB.Tools.TranslatorTool
{
	class QSBTranslatorScanBeam : MonoBehaviour
	{
		public Renderer _projectorRenderer;
		public Renderer _lightVolumeRenderer;

		const float _focusedBeamWidth = 0.25f;
		const float _maxBeamWidth = 1f;
		const float _maxBeamLength = 10f;
		const float _scanOffset = 0f;
		const float _switchLength = 0.33f;
		const float _fadeLength = 0.66f;

		public float _scanSpeed = 1f;
		public readonly Color _baseProjectorColor = new(0.3545942f, 2.206932f, 4.594794f, 1f);
		public readonly Color _baseLightColor = new(0.1301365f, 0.2158605f, 0.6239606f, 1f);
		public Quaternion _baseRotation;

		private bool _tooCloseToTarget;
		private NomaiTextLine _nomaiTextLine;
		private NomaiComputerRing _nomaiComputerRing;
		private NomaiVesselComputerRing _nomaiVesselComputerRing;
		private float _scanTime;
		private float _switchTime;
		private Quaternion _prevRotation;
		private Vector3 _prevScale;
		private float _fade;

		private void Awake()
		{
			_tooCloseToTarget = false;
			_prevRotation = Quaternion.identity;
			_prevScale = new Vector3(_maxBeamWidth, _maxBeamWidth, _maxBeamLength);
			_fade = 0f;

			if (_projectorRenderer != null)
			{
				_projectorRenderer.material.SetAlpha(0f);
				_projectorRenderer.enabled = false;
			}

			if (_lightVolumeRenderer != null)
			{
				_lightVolumeRenderer.material.SetAlpha(0f);
				_lightVolumeRenderer.enabled = false;
			}
		}

		private void OnDisable()
		{
			_tooCloseToTarget = false;
			_nomaiTextLine = null;
			_prevRotation = Quaternion.identity;
			_prevScale = new Vector3(_maxBeamWidth, _maxBeamWidth, _maxBeamLength);
			_fade = 0f;
			if (_projectorRenderer != null)
			{
				_projectorRenderer.material.SetAlpha(0f);
				_projectorRenderer.enabled = false;
			}

			if (_lightVolumeRenderer != null)
			{
				_lightVolumeRenderer.material.SetAlpha(0f);
				_lightVolumeRenderer.enabled = false;
			}

			transform.localRotation = _baseRotation;
			transform.localScale = _prevScale;
		}

		public bool IsSwitching()
			=> _switchTime < 1f;

		private void OnRenderObject()
		{
			if (!QSBCore.WorldObjectsReady || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug)
			{
				return;
			}

			Popcron.Gizmos.Line(transform.position, transform.position + transform.forward);
		}

		private void Update()
		{
			if (_nomaiTextLine != null && !_tooCloseToTarget)
			{
				_switchTime = Mathf.MoveTowards(_switchTime, 1f, Time.deltaTime / _switchLength);
				var smoothedSwitchTime = Mathf.SmoothStep(0f, 1f, _switchTime);
				_scanTime += Time.deltaTime * _scanSpeed;
				var num = (Mathf.Cos(_scanTime + _scanOffset) * 0.5f) + 0.5f;
				var pointAlongLine = _nomaiTextLine.GetPointAlongLine(num);
				var rhs = _nomaiTextLine.GetPointAlongLine(num + 0.1f) - _nomaiTextLine.GetPointAlongLine(num - 0.1f);
				var vector = pointAlongLine - transform.position;
				var upwards = Vector3.Cross(vector, rhs);
				var distance = Vector3.Distance(transform.position, pointAlongLine);
				var q = Quaternion.LookRotation(vector, upwards);
				var scanningRotation = transform.parent.InverseTransformRotation(q);
				transform.localRotation = Quaternion.Lerp(_prevRotation, scanningRotation, smoothedSwitchTime);
				transform.localScale = Vector3.Lerp(_prevScale, new Vector3(_focusedBeamWidth, _focusedBeamWidth, 1f + distance), smoothedSwitchTime);
			}
			else if (_nomaiComputerRing != null && !_tooCloseToTarget)
			{
				_switchTime = Mathf.MoveTowards(_switchTime, 1f, Time.deltaTime / _switchLength);
				var t2 = Mathf.SmoothStep(0f, 1f, _switchTime);
				_scanTime += Time.deltaTime * _scanSpeed;
				var t3 = (Mathf.Cos(_scanTime + _scanOffset) * 0.5f) + 0.5f;
				t3 = Mathf.Lerp(0.25f, 0.75f, t3);
				var pointOnRing = _nomaiComputerRing.GetPointOnRing(t3, transform.position);
				var forward = pointOnRing - transform.position;
				var up = _nomaiComputerRing.transform.up;
				var num3 = Vector3.Distance(transform.position, pointOnRing);
				var q2 = Quaternion.LookRotation(forward, up);
				var b2 = transform.parent.InverseTransformRotation(q2);
				transform.localRotation = Quaternion.Lerp(_prevRotation, b2, t2);
				transform.localScale = Vector3.Lerp(_prevScale, new Vector3(_focusedBeamWidth, _focusedBeamWidth, 1f + num3), t2);
			}
			else if (_nomaiVesselComputerRing != null && !_tooCloseToTarget)
			{
				_switchTime = Mathf.MoveTowards(_switchTime, 1f, Time.deltaTime / _switchLength);
				var smoothedSwitchTime = Mathf.SmoothStep(0f, 1f, _switchTime);

				_scanTime += Time.deltaTime * _scanSpeed;
				var t5 = (Mathf.Cos(_scanTime + _scanOffset) * 0.5f) + 0.5f;
				t5 = Mathf.Lerp(0.25f, 0.75f, t5);
				var pointOnRing2 = _nomaiVesselComputerRing.GetPointOnRing(t5, transform.position);
				var forward2 = pointOnRing2 - transform.position;
				var up2 = _nomaiVesselComputerRing.transform.up;
				var num4 = Vector3.Distance(transform.position, pointOnRing2);
				var q3 = Quaternion.LookRotation(forward2, up2);
				var b3 = transform.parent.InverseTransformRotation(q3);
				transform.localRotation = Quaternion.Lerp(_prevRotation, b3, smoothedSwitchTime);
				transform.localScale = Vector3.Lerp(_prevScale, new Vector3(_focusedBeamWidth, _focusedBeamWidth, 1f + num4), smoothedSwitchTime);
			}
			else
			{
				_switchTime = Mathf.MoveTowards(_switchTime, 1f, Time.deltaTime / _fadeLength);
				var t6 = Mathf.SmoothStep(0f, 1f, _switchTime * (2f - _switchTime));
				transform.localRotation = Quaternion.Lerp(_prevRotation, _baseRotation, _switchTime);
				transform.localScale = Vector3.Lerp(_prevScale, new Vector3(_maxBeamWidth, _maxBeamWidth, _maxBeamLength), t6);
			}

			var flag = !_tooCloseToTarget && (_nomaiTextLine != null || _nomaiComputerRing != null || _nomaiVesselComputerRing != null);

			_fade = Mathf.MoveTowards(
				_fade,
				flag
					? 1f
					: 0f,
				Time.deltaTime / _fadeLength * (_tooCloseToTarget
					? 3f
					: 1f));

			if (_projectorRenderer != null)
			{
				var shouldBeOn = _fade > 0f;
				if (_projectorRenderer.enabled != shouldBeOn)
				{
					_projectorRenderer.enabled = shouldBeOn;
				}

				if (_projectorRenderer.enabled)
				{
					_projectorRenderer.material.SetAlpha(_fade * _fade * _baseProjectorColor.a);
				}
			}

			if (_lightVolumeRenderer != null)
			{
				var shouldBeOn = _fade > 0f;
				if (_lightVolumeRenderer.enabled != shouldBeOn)
				{
					_lightVolumeRenderer.enabled = shouldBeOn;
				}

				if (_lightVolumeRenderer.enabled)
				{
					_lightVolumeRenderer.material.SetAlpha(_fade * _fade * _baseLightColor.a);
				}
			}
		}

		public void SetTooCloseToTarget(bool tooClose)
		{
			if (_tooCloseToTarget != tooClose)
			{
				_tooCloseToTarget = tooClose;
				_switchTime = 0f;
				_prevRotation = transform.localRotation;
				_prevScale = transform.localScale;
			}
		}

		public void SetNomaiTextLine(NomaiTextLine line)
		{
			if (_nomaiTextLine != line)
			{
				_switchTime = 0f;
				_nomaiTextLine = line;
				_prevRotation = transform.localRotation;
				_prevScale = transform.localScale;
			}
		}

		public void SetNomaiComputerRing(NomaiComputerRing ring)
		{
			if (_nomaiComputerRing != ring)
			{
				_switchTime = 0f;
				_nomaiComputerRing = ring;
				_prevRotation = transform.localRotation;
				_prevScale = transform.localScale;
			}
		}

		public void SetNomaiVesselComputerRing(NomaiVesselComputerRing ring)
		{
			if (_nomaiVesselComputerRing != ring)
			{
				_switchTime = 0f;
				_nomaiVesselComputerRing = ring;
				_prevRotation = transform.localRotation;
				_prevScale = transform.localScale;
			}
		}
	}
}
