using Dev.Scripts.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Movable : MonoBehaviour, IMovable
{
    [SerializeField] internal EMovableType _movableShapeType;
    [SerializeField] internal MovableChild _movableChildPrefab;
    [SerializeField] internal List<MovableChild> _movableChilds = new List<MovableChild>();
    [SerializeField] internal Vector3 _holderScale;
    [SerializeField] internal Vector3 _holderPosition;
    [SerializeField] internal float _holderScaleMultiplier;
    [SerializeField] internal float _holderMaxXorY;
    [SerializeField] internal bool _dragging;
    [SerializeField] internal MovableHolder _holder;
    [SerializeField] internal Vector3 _draggingOffset;
    internal List<Coordinate> coordinates;
    internal Color color;
    public virtual void Init(EMovableType movableType, MovableHolder holder)
    {
        _movableShapeType = movableType;
        coordinates = TypeDictionary.Movable.CoordinateDictionary[_movableShapeType];
        color = TypeDictionary.Movable.ColorDictionary[_movableShapeType];
        _holder = holder;

        SetChilds();
        SetHolderScale();
        SetHolderPosition();
    }
    internal virtual void SetChilds()
    {
        for (int i = 0; i < coordinates.Count; i++)
        {
            MovableChild child = Instantiate(_movableChildPrefab, transform);
            child.Init(i, coordinates[i], color, this, GetCenteringPositionOffset());
            _movableChilds.Add(child);
        }
    }
    internal virtual Vector3 GetCenteringPositionOffset()
    {
        var maxX = coordinates.Max(j => j.X);
        var maxY = coordinates.Max(j => j.Y);
        var max = Mathf.Max(maxX, maxY);
        return new Vector3(-maxX * 0.5f, maxY * 0.5f, 0) * transform.localScale.x;
    }
    internal virtual void SetHolderScale()
    {
        _holderScale = transform.localScale / (_holderMaxXorY) * _holderScaleMultiplier;
        transform.localScale = _holderScale;
    }
    internal virtual void SetHolderPosition()
    {
        transform.position = new Vector3(transform.position.x, transform.position.y, 0);
    }
    internal virtual void Update()
    {
        if (_dragging)
        {
            Vector3 screenToWorldPosition = CameraManager.Instance.Camera.ScreenToWorldPoint(Input.mousePosition);
            screenToWorldPosition.z = 0;
            transform.position = screenToWorldPosition + _draggingOffset;
        }
    }
    internal virtual void OnEnable()
    {
        App_EventManager.OnMovableMouseDown += OnMovableMouseDown;
        App_EventManager.OnMovableMouseUp += OnMovableMouseUp;
    }
    internal virtual void OnDisable()
    {
        App_EventManager.OnMovableMouseDown -= OnMovableMouseDown;
        App_EventManager.OnMovableMouseUp -= OnMovableMouseUp;
    }
    internal virtual void OnMovableMouseDown(IMovable movable)
    {
        if (!ReferenceEquals(this, movable)) return;
        transform.parent = null;
        transform.localScale = Vector3.one;
        _dragging = true;
        foreach (var movableChild in _movableChilds)
        {
            movableChild.SetRenderOrder(2);
            if (movableChild.Attached)
                DeattachOnMouseDown(movableChild);
        }
    }
    internal virtual void OnMovableMouseUp(IMovable movable)
    {
        if (!ReferenceEquals(this, movable)) return;
        transform.parent = _holder.transform;
        transform.localPosition = _holderPosition;
        transform.localScale = _holderScale;
        transform.position = new Vector3(transform.position.x, transform.position.y, 0);
        _dragging = false;
        bool allTriggered = _movableChilds.All(j => j.HolderTriggeredCollider != null);
        bool allAvailable = allTriggered ? _movableChilds.All(j => j.HolderTriggeredCollider.IsAvailable) : false;
        foreach (var movableChild in _movableChilds)
        {
            movableChild.SetRenderOrder(1);
            if (allAvailable && allTriggered)
                AttachOnMouseUp(movableChild);
        }
    }
    internal virtual void AttachOnMouseUp(MovableChild movableChild)
    {
        movableChild.transform.parent = ((BoardTile)movableChild.HolderTriggeredCollider).transform;
        movableChild.transform.localScale = Vector3.one;
        movableChild.Attach(movableChild.HolderTriggeredCollider);
    }
    internal virtual void DeattachOnMouseDown(MovableChild movableChild)
    {
        movableChild.transform.parent = transform;
        movableChild.transform.localScale = Vector3.one;
        movableChild.Deattach(movableChild.HolderTriggeredCollider);
    }
    public virtual void Destroy()
    {
        Destroy(gameObject);
    }
}
