using Microsoft.Unity.VisualStudio.Editor;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Tilemaps;

struct Kafel
{
    //testowa struktura
    //z infem o pojedynczym kaflu
    public int kolumna, wiersz;
    public Tile tile;
}

struct TPoint
{
    //dane dla tablicy mapy swiata
    public int x,y;
    //dane dla tablicy Tilsw
    public Vector3Int pozycja;
}

public class Droga2D : MonoBehaviour
{
    //SteTile-metoda ustaw kafla w mapie
    //SwapTile- zmienia kafle jednego typu na inne
    //WorldToCell- przeoenie pozycji w grze
    /// </summary>
    [SerializeField] private Grid grid;
    [SerializeField] private Tilemap warstwaGruntu,
                                     warstwaSciezki,
                                     warstwaRzeczy;
    [SerializeField] private TileBase bmpStart, bmpMeta, bmpSciezka;
    //lista z kafelkami po ktrych mona chodzi
    [SerializeField] private List<Tile> listaKafleDrogi;
    

    private Kafel kafel;
    private int ileKolumn, ileWierszy;
    private bool fStart = false;

    int[,] kierunek=new int[4, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } };
    //int[,] kierunek = new int[8, 2]{{-1,-1},{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0}};
    byte[,] MapaSwiata = null;

    Vector3Int pozycjaStartu, pozycjaMety;

    List<TPoint> Szlak(byte[,] Mapa, 
                    Vector3Int pozycjaStartu, 
                    Vector3Int pozycjaMety
                    )
    {
        bool fMeta=false;
        int row,col,Zalazek,L;
        List<TPoint> tabKolejka=new List<TPoint>(),
                     tabBufor= new List<TPoint>();
        TPoint _Start,_Cel;
        TPoint p = new TPoint();
        int ileWierszy=Mapa.GetLength(0);
        int ileKolumn=Mapa.GetLength(1);
        int[,] ileOdwiedzin=new int[ileWierszy, ileKolumn];
        bool[,] tabOdwiedzin = new bool[ileWierszy, ileKolumn];
        //wypelnij tablice odwiedzin ZERAMI,tablic testu logicznego ustaw na false
        for (int w = 0; w < ileWierszy; w++)
            for (int k= 0; k < ileKolumn; k++)
            {
                ileOdwiedzin[w, k] = 0;
                tabOdwiedzin[w, k] = false;
            }
        _Start.x = ileKolumn / 2 + pozycjaStartu.x;
        _Start.y = ileWierszy / 2 - pozycjaStartu.y - 1;
        _Start.pozycja = pozycjaStartu;
        tabKolejka.Add( _Start );
        tabOdwiedzin[_Start.y, _Start.x]= true;
        _Cel.y= ileWierszy / 2 - pozycjaMety.y - 1;
        _Cel.x= ileKolumn / 2 + pozycjaMety.x;
        _Cel.pozycja= pozycjaMety;
        int ile = 0;
        while (!fMeta)
        {
           for(int j=0;j<tabKolejka.Count;j++)
            {
              //ptal dla 4 lub 8 kierunkw szukania drogi
              for(int k = 0; k < kierunek.GetLength(0);k++)
                {
                col= tabKolejka[j].x + kierunek[k, 0];
                row= tabKolejka[j].y + kierunek[k, 1];
                if (col < 0 || col > ileKolumn - 1 || row < 0 || row > ileWierszy - 1 || Mapa[row, col] != 0) continue;
                if (tabOdwiedzin[row, col] == false)
                        {
                            ileOdwiedzin[row, col]= ileOdwiedzin[tabKolejka[j].y,tabKolejka[j].x]+1;
                            tabOdwiedzin[row, col] = true;
                            p.x = col;
                            p.y= row;
                            p.pozycja = pozycja_z_Wiersza_i_Kolumny(p.y, p.x);
                            tabBufor.Add(p);
                            if (_Cel.x == col && _Cel.y == row)
                            {
                                fMeta = true;
                                break;//wyskocz z ptli k
                            }
                        }//koniec if-a tabodwiedzin
                    //}//koniec glownego if-a
                }//koniec petli dla kierunkow
            }//koniec petli dla biezacej kolejki
            tabKolejka.Clear();
            //skopijuj bufor tablicy kolejki
            for (int i = 0; i < tabBufor.Count; i++)
                tabKolejka.Add(tabBufor[i]);
            tabBufor.Clear();
            ile++;
            //nie znaleziono drogi
            if (ile > ileWierszy * ileKolumn) return tabKolejka;
        }//koniec while
        Zalazek = ileOdwiedzin[_Cel.y, _Cel.x];
        tabKolejka.Clear();
        p.x = _Cel.x;
        p.y = _Cel.y;
        p.pozycja = _Cel.pozycja;
        //UWAGA. Szlak budowany jest od koca, czyli od mety do startu
        //i zapisywany jest w tabKolejka
        tabKolejka.Add(p);
        fMeta = false;
        ile = 0;
        while (!fMeta)
        {
            //ptal dla 4 lub 8 kierunkw szukania drogi
            for (int k = 0; k < kierunek.GetLength(0); k++)
            {
                col = tabKolejka[tabKolejka.Count - 1].x + kierunek[k, 0];
                row = tabKolejka[tabKolejka.Count - 1].y + kierunek[k, 1];
                if (col < 0 || col > ileKolumn - 1 || row < 0 || row > ileWierszy - 1 || Mapa[row, col] != 0) continue;
                {
                    L = ileOdwiedzin[row,col];
                    if (L == Zalazek-1)
                    {
                        Zalazek = L;
                        p.x = col;
                        p.y = row;
                        p.pozycja = pozycja_z_Wiersza_i_Kolumny(p.y, p.x);
                        tabKolejka.Add(p);
                    }
                    if (col == _Start.x && row == _Start.y)
                    {
                        fMeta = true;
                        //wyskocz z ptli k
                        break;
                    }
                }
                ile++;
                if (ile > ileWierszy * ileKolumn) return tabKolejka;
            }
        }//koniec while
        //pokaz w debugerze licznik odwiedzin
        for (int w = 0; w < ileWierszy; w++)
        {
            string s = null;
            for (int k = 0; k < ileKolumn; k++)
            {
                s = s + ileOdwiedzin[w, k]+" ";
            }
            Debug.Log(s);
        }
        //zwr szlak
        return tabKolejka;
    }
    // Start is called before the first frame update
    void Start()
    {
        //warstwaGruntu.CompressBounds();
        ileKolumn = warstwaGruntu.size.x;
        ileWierszy = warstwaGruntu.size.y;
        RobMape(warstwaGruntu);

        Debug.Log("Rozmiar swiata: " + warstwaGruntu.size);
        Debug.Log("Ile kolumn: " + ileKolumn);
        Debug.Log("Ile wierszy: " + ileWierszy);
        Debug.Log("Mapa swiata: " + MapaSwiata);
    }

    void RobMape(Tilemap warstwa)
    {
        MapaSwiata = new byte[ileWierszy, ileKolumn];
        for (int w = 0; w < ileWierszy; w++)
        {
            string s = null;
            for (int k = 0; k < ileKolumn; k++)
            {
                //przyjmij e jest mur
                MapaSwiata[w, k] = 1;
                Tile t = (Tile)warstwaGruntu.GetTile(pozycja_z_Wiersza_i_Kolumny(w, k));
                foreach(Tile tt in listaKafleDrogi)
                {
                    if (t == tt)
                    {
                        //wstaw drog
                        MapaSwiata[w, k] = 0;
                        break;
                    }
                }
                //wylij do podgldu debugera
                s += MapaSwiata[w, k]+" ";
            }
            Debug.Log(s);
        }
    }

    Vector3Int pozycja_z_Wiersza_i_Kolumny(int wiersz, int kolumna)
    {
        Vector3Int vektor3int = new Vector3Int();

        vektor3int.x = kolumna - ileKolumn / 2;
        vektor3int.y = ileWierszy / 2 - 1 - wiersz;
        return vektor3int;
    }
    void StartMeta(Vector3Int pozycja)
    {
        if (!fStart)
        {
            //usu stary kafel startu
            warstwaRzeczy.SetTile(pozycjaStartu, null);
            //ustwa kafel startu
            pozycjaStartu = pozycja;
            warstwaRzeczy.SetTile(pozycjaStartu, bmpStart);
        }
        else
        {
            //usu stary kafel mety
            warstwaRzeczy.SetTile(pozycjaMety, null);
            //ustwa kafel mety
            pozycjaMety = pozycja;
            warstwaRzeczy.SetTile(pozycjaMety, bmpMeta);
        }
        fStart =!fStart;
    }

    void PodajStartMeta()
    {
        Vector3 mp=Camera.main.ScreenToWorldPoint(Input.mousePosition);
        Vector3Int pozycja= warstwaGruntu.WorldToCell(mp);
        if(warstwaGruntu.GetTile(pozycja) != null )
        {
            //testowe info o kliknitym kaflu
            kafel.kolumna = ileKolumn/2 + pozycja.x;
            kafel.wiersz= ileWierszy/2 - pozycja.y -1;
            kafel.tile = (Tile)warstwaGruntu.GetTile(pozycja);
            Debug.Log("pozycja " + pozycja);
            Debug.Log("klikniety kafel "+kafel.tile);
            Debug.Log("klikniety kafel kolumna " + kafel.kolumna);
            Debug.Log("klikniety kafel wiersz " + kafel.wiersz);
            StartMeta(pozycja);
        }
    }

    // Update is called once per frame
    void Update()
    {
        //kliknij lewym w kafel mapy
        if (Input.GetMouseButtonDown(0))
        {
            //
            PodajStartMeta();
            //czysc stary szlak
            warstwaSciezki.ClearAllTiles();
            //rysuj nowy szlak
            foreach (TPoint p in Szlak(MapaSwiata, pozycjaStartu, pozycjaMety))
            warstwaSciezki.SetTile(p.pozycja, bmpSciezka);
        }
    }
}
