package it.polimi.ingsw.gc14.Model;

import com.google.gson.*;
import it.polimi.ingsw.gc14.Model.Cards.Building.EffectType;
import it.polimi.ingsw.gc14.Model.Cards.Building.Effects.*;
import it.polimi.ingsw.gc14.Model.Cards.BuildingCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.CharacterType;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.*;
import it.polimi.ingsw.gc14.Model.Cards.TribeCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Events.CavePaintings;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Events.Hunt;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Events.ShamanicRitual;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Events.Sustenance;

import java.io.*;
import java.lang.reflect.Type;
import java.util.*;


public class DecksCreator {

    public static List<TribeCard> loadTribeDeckByEra(int era) throws IllegalArgumentException
    {
        return switch (era) {
            case 1 -> loadTribeDeck("/Cards/tribe_era1.json");
            case 2 -> loadTribeDeck("/Cards/tribe_era2.json");
            case 3 -> loadTribeDeck("/Cards/tribe_era3.json");
            default -> throw new IllegalArgumentException();
        };
    }
    public static List<TribeCard> loadTribeDeck(String resourcePath) {
        Gson gson = new Gson();
        Type listType = new com.google.gson.reflect.TypeToken<List<TribeCardDefinition>>(){}.getType();

        InputStream is = DecksCreator.class.getResourceAsStream(resourcePath);
        if (is == null) {
            throw new RuntimeException("File non trovato: " + resourcePath);
        }

        try (Reader reader = new InputStreamReader(is)) {
            List<TribeCardDefinition> definitions = gson.fromJson(reader, listType);
            List<TribeCard> cards = new ArrayList<>();
            for (TribeCardDefinition def : definitions) {
                cards.add(createCard(def));
            }
            return cards;
        } catch (IOException e) {
            throw new RuntimeException("Errore caricamento mazzo: " + resourcePath, e);
        }
    }
    public static  List<BuildingCard> loadBuildingDeckByEra(int era) throws IllegalArgumentException
    {
        if(era<=0 || era>3) throw new IllegalArgumentException();
        return loadBuildingDeck("/Cards/buildingCards.json").stream().filter(x->x.getEra()==era).toList();
    }
    public static List<BuildingCard> loadBuildingDeck(String resourcePath) {
        Gson gson = new Gson();
        Type listType = new com.google.gson.reflect.TypeToken<List<BuildingCardDefinition>>(){}.getType();

        InputStream is = DecksCreator.class.getResourceAsStream(resourcePath);
        if (is == null) {
            throw new RuntimeException("File non trovato: " + resourcePath);
        }

        try (Reader reader = new InputStreamReader(is)) {
            List<BuildingCardDefinition> definitions = gson.fromJson(reader, listType);
            List<BuildingCard> cards = new ArrayList<>();
            for (BuildingCardDefinition def : definitions) {
                cards.add(createCard(def));
            }
            return cards;
        } catch (IOException e) {
            throw new RuntimeException("Errore caricamento mazzo: " + resourcePath, e);
        }
    }

    public static List<Slot> loadSlotDeck()
    {
        List<Slot> slots = new ArrayList<>();
        char[]chars={'A','B','C','D','E','F','G'};
        for(char c : chars)
            slots.add(new Slot(c));
        return slots;
    }
    private static TribeCard createCard(TribeCardDefinition def) {
        int era = def.era;

        int[] p = def.params.stream().mapToInt(d -> ((Double) d).intValue()).toArray();
        if(def.isEvent)
        {
            return switch (def.type) {
                case "Sustenance" -> new Sustenance(era,p[0]);
                case "Hunt" -> new Hunt(era,p[0]);
                case "CavePaintings" -> new CavePaintings(era,p[0],p[1],p[2]);
                case "ShamanicRitual" -> new ShamanicRitual(era,p[0],p[1]);
                default -> throw new IllegalArgumentException("Tipo sconosciuto: " + def.type);
            };
        }
        return switch (def.type) {
            case "Hunter" -> p.length == 0
                    ? new Hunter(era, def.armed)
                    : new Hunter(era, def.armed, p[0]);
            case "Builder" -> switch (p.length) {
                case 2 -> new Builder(era, p[0], p[1]);
                case 3 -> new Builder(era, p[0], p[1], p[2]);
                default -> throw new IllegalArgumentException("Builder: parametri non validi");
            };
            case "Gatherer" -> switch (p.length) {
                case 0 -> new Gatherer(era);
                case 1 -> new Gatherer(era, p[0]);
                default -> throw new IllegalArgumentException("Gatherer: parametri non validi");
            };
            case "Artist" -> switch (p.length) {
                case 0 -> new Artist(era);
                case 1 -> new Artist(era, p[0]);
                default -> throw new IllegalArgumentException("Artist: parametri non validi");
            };
            case "Inventor" -> switch (p.length) {
                case 1 -> new Inventor(era, p[0]);
                case 2 -> new Inventor(era, p[0], p[1]);
                default -> throw new IllegalArgumentException("Inventor: parametri non validi");
            };
            case "Shaman" -> switch (p.length) {
                case 1 -> new Shaman(era, p[0]);
                case 2 -> new Shaman(era, p[0], p[1]);
                default -> throw new IllegalArgumentException("Shaman: parametri non validi");
            };
            default -> throw new IllegalArgumentException("Tipo sconosciuto: " + def.type);
        };
    }

    private static BuildingCard createCard(BuildingCardDefinition def) {
        return switch (def.effectId) {
            case 0 -> new Building0(def.era, def.price, def.prestigeValue);
            case 1 -> new Building1(def.era, def.price, def.prestigeValue, CharacterType.valueOf(((String) def.params.get(0)).toUpperCase()));
            case 4 -> new Building4(def.era, def.price, def.prestigeValue);
            case 8 -> new Building8(def.era, def.price, def.prestigeValue);
            case 10 -> new Building10(def.era, def.price, def.prestigeValue);
            case 11 -> new Building11(def.era, def.price, def.prestigeValue, CharacterType.valueOf(((String) def.params.get(0)).toUpperCase()), ((Double) def.params.get(1)).intValue());
            case 13 -> new Building13(def.era, def.price, def.prestigeValue);
            default -> new BuildingCard(def.effectId, def.era, def.price, def.prestigeValue);
        };

    }


    private static class TribeCardDefinition {
        String type;
        int era;
        boolean armed;
        boolean isEvent;
        List<Object> params; // Object per gestire boolean e int misti
    }

    private static class BuildingCardDefinition {
        int effectId;
        int era;
        int price;
        int prestigeValue;
        List<Object> params; // Object per gestire boolean e int misti
    }
}