﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Assets.Helpers;
using Assets.Models.Factories;
using UniRx;
using UnityEngine;

namespace Assets.Models
{
    public class DynamicTileManager : TileManager
    {
        private Vector2 _tileSize;
        [SerializeField] private BoxCollider _centerCollider;
        [SerializeField] private Transform _player;
        [SerializeField] private int _removeAfter;

        public override void Init(BuildingFactory buildingFactory, RoadFactory roadFactory, World.Settings settings)
        {
            base.Init(buildingFactory, roadFactory, settings);
            _tileSize = Tiles.Values.First().Rect.size;
            _centerCollider.transform.localScale *= _tileSize.x;

            Observable.Interval(TimeSpan.FromSeconds(2)).Subscribe(x => { UpdateTiles(); });
        }

        private void UpdateTiles()
        {
            if (!_centerCollider.bounds.Contains(_player.transform.position))
            {
                //player movement in TMS tiles
                var tileDif = GetMovementVector();
                //move locals
                Centralize(tileDif);
                //create new tiles
                LoadTiles(CenterTms, CenterInMercator);
                UnloadTiles(CenterTms);
            }
        }

        private void Centralize(Vector2 tileDif)
        {
            //move everything to keep current tile at 0,0
            foreach (var tile in Tiles.Values)
            {
                tile.transform.position -= new Vector3(tileDif.x * _tileSize.x, 0, tileDif.y * _tileSize.y);
            }
            CenterTms += tileDif;
            CenterInMercator = GM.TileBounds(CenterTms, Zoom).center;
            var difInUnity = new Vector3(tileDif.x*_tileSize.x, 0, tileDif.y*_tileSize.y);
            _player.position -= difInUnity;
            Camera.main.transform.position -= difInUnity;
        }
        
        private void UnloadTiles(Vector2 currentTms)
        {
            var rem = new List<Vector2>();
            foreach (var key in Tiles.Keys.Where(x => x.ManhattanTo(currentTms) > _removeAfter))
            {
                rem.Add(key);
                Destroy(Tiles[key].gameObject);
            }
            foreach (var v in rem)
            {
                Tiles.Remove(v);
            }
        }

        private Vector2 GetMovementVector()
        {
            var dif = _player.transform.position.ToVector2xz();
            var tileDif = Vector2.zero;
            if (dif.x < _centerCollider.bounds.min.x)
                tileDif.x = -1;
            else if (dif.x > _centerCollider.bounds.max.x)
                tileDif.x = 1;

            if (dif.y < _centerCollider.bounds.min.y)
                tileDif.y = 1;
            else if (dif.y > _centerCollider.bounds.max.y)
                tileDif.y = -1; //invert axis  TMS vs unity
            return tileDif;
        }
    }
}
