package com.ygames.ysoccer.screens;

import com.badlogic.gdx.files.FileHandle;
import com.ygames.ysoccer.competitions.League;
import com.ygames.ysoccer.framework.Assets;
import com.ygames.ysoccer.framework.GLGame;
import com.ygames.ysoccer.framework.GLScreen;
import com.ygames.ysoccer.gui.Button;
import com.ygames.ysoccer.gui.Label;
import com.ygames.ysoccer.gui.MenuTheme;
import com.ygames.ysoccer.gui.Widget;
import com.ygames.ysoccer.match.Const;
import com.ygames.ysoccer.match.Player;
import com.ygames.ysoccer.match.Team;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;

import static com.ygames.ysoccer.framework.Assets.fileComparatorByName;
import static com.ygames.ysoccer.framework.Assets.font10;
import static com.ygames.ysoccer.framework.Assets.font14;
import static com.ygames.ysoccer.framework.Assets.gettext;
import static com.ygames.ysoccer.framework.Font.Align.CENTER;
import static com.ygames.ysoccer.framework.Font.Align.LEFT;
import static com.ygames.ysoccer.match.Team.Type.CLUB;

class ManagerTransferBrowse extends GLScreen {

    private static final int PAGE_SIZE = 17;

    private final League league;
    private final Team managerTeam;
    private final FileHandle folder;
    private final String selectedLeague;
    private final Team selectedTeam;
    private final int page;
    private final String status;
    private final String pendingOfferKey;
    private final double pendingOfferPrice;

    ManagerTransferBrowse(GLGame game) {
        this(game, getTransferRootFolder(game), null, null, 0, "", "", 0);
    }

    private ManagerTransferBrowse(GLGame game, FileHandle folder, String selectedLeague, Team selectedTeam,
                                  int page, String status, String pendingOfferKey, double pendingOfferPrice) {
        super(game);
        this.league = (League) game.competition;
        this.managerTeam = findManagerTeam();
        ManagerEconomy.ensureBudget(managerTeam, game.settings.playerPriceFactor);
        this.folder = folder;
        this.selectedLeague = selectedLeague;
        this.selectedTeam = selectedTeam;
        this.page = Math.max(0, Math.min(page, maxPlayerPage(selectedTeam)));
        this.status = status;
        this.pendingOfferKey = pendingOfferKey;
        this.pendingOfferPrice = pendingOfferPrice;

        background = game.stateBackground;

        Widget w;

        w = new TitleBar("MANAGER MODE - TRANSFERS", game.stateColor.body);
        widgets.add(w);

        addBreadcrumb();

        w = new HeaderLabel();
        widgets.add(w);

        w = new StatusLabel();
        widgets.add(w);

        if (selectedTeam != null) {
            addPlayerButtons();
        } else if (folder.list(Assets.teamFilenameFilter).length > 0) {
            addLeagueOrTeamButtons();
        } else {
            addFolderButtons();
        }

        w = new AllPlayersButton();
        widgets.add(w);

        w = new BackButton();
        widgets.add(w);

        w = new ExitButton();
        widgets.add(w);

        if (getSelectedWidget() == null) {
            setSelectedWidget(w);
        }
    }

    private Team findManagerTeam() {
        for (Team team : league.teams) {
            if (team.path != null && team.path.equals(league.managerTeamPath)) {
                return team;
            }
        }
        for (Team team : league.teams) {
            if (team.controlMode == Team.ControlMode.PLAYER) {
                return team;
            }
        }
        return league.teams.get(0);
    }

    private void addBreadcrumb() {
        ArrayList<Widget> breadcrumb = new ArrayList<>();

        FileHandle fh = folder;
        boolean isDataRoot;
        do {
            isDataRoot = fh.equals(Assets.teamsRootFolder);
            Widget w = new BreadCrumbButton(fh, isDataRoot);
            breadcrumb.add(w);
            fh = fh.parent();
        } while (!isDataRoot);

        Collections.reverse(breadcrumb);

        if (selectedLeague != null) {
            breadcrumb.add(new LeagueCrumbButton());
        }
        if (selectedTeam != null) {
            breadcrumb.add(new TeamCrumbLabel());
        }

        int x = (game.gui.WIDTH - 960) / 2;
        for (Widget b : breadcrumb) {
            b.setPosition(x, 72);
            x += b.w + 2;
        }
        widgets.addAll(breadcrumb);
    }

    private void addFolderButtons() {
        ArrayList<Widget> list = new ArrayList<>();

        ArrayList<FileHandle> files = new ArrayList<>(Arrays.asList(folder.list()));
        Collections.sort(files, fileComparatorByName);
        for (FileHandle file : files) {
            if (file.isDirectory()) {
                Widget w = new FolderButton(file);
                list.add(w);
                widgets.add(w);
            }
        }

        if (list.size() > 0) {
            Widget.arrange(game.gui.WIDTH, 380, 34, 20, list);
            setSelectedWidget(list.get(0));
        } else {
            Widget w = new EmptyLabel("NO FOLDERS HERE");
            widgets.add(w);
        }
    }

    private void addLeagueOrTeamButtons() {
        ArrayList<String> leagues = loadLeagueNames();
        String activeLeague = selectedLeague;
        if (activeLeague == null && leagues.size() == 1) {
            activeLeague = leagues.get(0);
        }

        ArrayList<Widget> list = new ArrayList<>();
        if (activeLeague == null && leagues.size() > 1) {
            for (String league : leagues) {
                Widget w = new LeagueButton(league);
                list.add(w);
                widgets.add(w);
            }
            Widget.arrange(game.gui.WIDTH, 380, 34, 20, list);
            setSelectedWidget(list.get(0));
            return;
        }

        FileHandle[] teamFileHandles = folder.list(Assets.teamFilenameFilter);
        for (FileHandle teamFileHandle : teamFileHandles) {
            Team team = Assets.json.fromJson(Team.class, teamFileHandle.readString("UTF-8"));
            team.path = normalizeTeamPath(Assets.getRelativeTeamPath(teamFileHandle));
            if (team.type == CLUB && !isManagerTeam(team)
                    && (activeLeague == null || activeLeague.equals(team.league))) {
                Widget w = new TeamButton(team, activeLeague);
                list.add(w);
                widgets.add(w);
            }
        }

        if (list.size() > 0) {
            Collections.sort(list, Widget.widgetComparatorByText);
            Widget.arrange(game.gui.WIDTH, 380, 30, 20, list);
            setSelectedWidget(list.get(0));
        } else {
            Widget w = new EmptyLabel("NO CLUBS HERE");
            widgets.add(w);
        }
    }

    private ArrayList<String> loadLeagueNames() {
        ArrayList<String> names = new ArrayList<>();
        FileHandle leaguesFile = folder.child("leagues.json");
        if (leaguesFile.exists()) {
            Collections.addAll(names, Assets.json.fromJson(String[].class, leaguesFile.readString("UTF-8")));
            Collections.sort(names);
            return names;
        }

        FileHandle[] teamFileHandles = folder.list(Assets.teamFilenameFilter);
        for (FileHandle teamFileHandle : teamFileHandles) {
            Team team = Assets.json.fromJson(Team.class, teamFileHandle.readString("UTF-8"));
            if (team.type == CLUB && team.league != null && !names.contains(team.league)) {
                names.add(team.league);
            }
        }
        Collections.sort(names);
        return names;
    }

    private void addPlayerButtons() {
        ArrayList<TransferCandidate> candidates = buildTeamCandidates(selectedTeam);
        int start = page * PAGE_SIZE;
        int end = Math.min(start + PAGE_SIZE, candidates.size());

        for (int i = start; i < end; i++) {
            Widget w = new PlayerButton(candidates.get(i), 128 + 28 * (i - start));
            widgets.add(w);
            if (i == start) {
                setSelectedWidget(w);
            }
        }

        if (candidates.size() == 0) {
            Widget w = new EmptyLabel("NO PLAYERS AVAILABLE");
            widgets.add(w);
        }

        Widget w = new PrevPlayerButton(candidates.size());
        widgets.add(w);

        w = new NextPlayerButton(candidates.size());
        widgets.add(w);
    }

    private ArrayList<TransferCandidate> buildTeamCandidates(Team team) {
        ArrayList<TransferCandidate> list = new ArrayList<>();
        for (Player player : team.players) {
            if (!alreadyInManagerSquad(player)) {
                list.add(new TransferCandidate(team, player));
            }
        }
        Collections.sort(list, new TransferCandidateComparator());
        return list;
    }

    private int maxPlayerPage(Team team) {
        if (team == null) {
            return 0;
        }
        int count = 0;
        for (Player player : team.players) {
            if (!alreadyInManagerSquad(player)) {
                count++;
            }
        }
        return Math.max(0, (count - 1) / PAGE_SIZE);
    }

    private boolean alreadyInManagerSquad(Player player) {
        for (Player owned : managerTeam.players) {
            if (samePlayer(owned, player)) {
                return true;
            }
        }
        return false;
    }

    private boolean samePlayer(Player a, Player b) {
        return safeEquals(a.name, b.name)
                && safeEquals(a.shirtName, b.shirtName)
                && safeEquals(a.nationality, b.nationality)
                && a.role == b.role
                && a.value == b.value;
    }

    private boolean safeEquals(String a, String b) {
        return a == null ? b == null : a.equals(b);
    }

    private boolean isManagerTeam(Team team) {
        return normalizeTeamPath(managerTeam.path).equals(normalizeTeamPath(team.path));
    }

    private void negotiate(TransferCandidate candidate) {
        if (managerTeam.players.size() >= Const.FULL_TEAM) {
            game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, selectedTeam, page,
                    "SQUAD FULL", "", 0));
            return;
        }

        String key = candidateKey(candidate);
        if (!key.equals(pendingOfferKey)) {
            double askingPrice = askingPrice(candidate);
            String text = candidate.team.name + " WANT " + formatMoney(askingPrice)
                    + " FOR " + candidate.player.shirtName + " - CLICK AGAIN TO ACCEPT";
            game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, selectedTeam, page,
                    text, key, askingPrice));
            return;
        }

        if (managerTeam.transferBudget < pendingOfferPrice) {
            String text = "NOT ENOUGH MONEY - NEED " + formatMoney(pendingOfferPrice)
                    + ", HAVE " + formatMoney(managerTeam.transferBudget);
            game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, selectedTeam, page,
                    text, "", 0));
            return;
        }

        ManagerEconomy.ensureBudget(candidate.team, game.settings.playerPriceFactor);
        managerTeam.transferBudget -= pendingOfferPrice;
        candidate.team.transferBudget += pendingOfferPrice;
        candidate.team.players.remove(candidate.player);
        managerTeam.players.add(candidate.player);
        candidate.player.team = managerTeam;

        String text = "SIGNED " + candidate.player.shirtName + " FROM " + candidate.team.name
                + " FOR " + formatMoney(pendingOfferPrice);
        game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, candidate.team, page,
                text, "", 0));
    }

    private String candidateKey(TransferCandidate candidate) {
        return normalizeTeamPath(candidate.team.path) + "::"
                + candidate.player.name + "::"
                + candidate.player.shirtName + "::"
                + candidate.player.nationality + "::"
                + candidate.player.role + "::"
                + candidate.player.getValue();
    }

    private double askingPrice(TransferCandidate candidate) {
        double basePrice = game.settings.playerPriceFactor * Const.playerPrices[candidate.player.getValue()];
        int markup = 15 + Math.max(0, candidate.player.getValue() - 34) * 3;
        if (candidate.team.players.size() <= Const.BASE_TEAM) {
            markup += 30;
        } else if (candidate.team.players.size() <= Const.BASE_TEAM + 2) {
            markup += 15;
        }
        return basePrice * (100 + markup) / 100.0;
    }

    private String formatMoney(double price) {
        return game.settings.currency + " " + Assets.moneyFormat(price);
    }

    private static FileHandle getTransferRootFolder(GLGame game) {
        if (game.competition instanceof League) {
            League league = (League) game.competition;
            if (league.files != null && league.files.folder != null) {
                String folder = normalizeTeamPath(league.files.folder);
                int clubTeamsIndex = folder.indexOf("/CLUB_TEAMS");
                if (clubTeamsIndex != -1) {
                    return Assets.teamsRootFolder.child(folder.substring(0, clubTeamsIndex + "/CLUB_TEAMS".length()));
                }
            }
        }

        FileHandle defaultRoot = Assets.teamsRootFolder.child("2024-25/CLUB_TEAMS");
        return defaultRoot.exists() ? defaultRoot : Assets.teamsRootFolder;
    }

    private static String normalizeTeamPath(String path) {
        if (path == null) {
            return "";
        }
        int dataTeams = path.indexOf("data/teams/");
        if (dataTeams != -1) {
            path = path.substring(dataTeams + "data/teams/".length());
        }
        while (path.startsWith("/")) {
            path = path.substring(1);
        }
        return path;
    }

    private class HeaderLabel extends Label {

        HeaderLabel() {
            String text = managerTeam.name + "  BUDGET " + formatMoney(managerTeam.transferBudget)
                    + "  SQUAD " + managerTeam.players.size() + "/" + Const.FULL_TEAM;
            if (selectedTeam != null) {
                text += "  BUYING FROM " + selectedTeam.name;
            }
            setGeometry((game.gui.WIDTH - 960) / 2, 92, 960, 24);
            setText(text, CENTER, font10);
        }
    }

    private class StatusLabel extends Label {

        StatusLabel() {
            setGeometry((game.gui.WIDTH - 960) / 2, 108, 960, 24);
            setText(status, CENTER, font10);
        }
    }

    private class EmptyLabel extends Label {

        EmptyLabel(String text) {
            setGeometry((game.gui.WIDTH - 960) / 2, 300, 960, 32);
            setText(text, CENTER, font14);
        }
    }

    private class BreadCrumbButton extends Button {

        private final FileHandle crumbFolder;

        BreadCrumbButton(FileHandle folder, boolean isDataRoot) {
            this.crumbFolder = folder;
            setSize(0, 32);
            if (folder.equals(ManagerTransferBrowse.this.folder) && selectedLeague == null && selectedTeam == null) {
                setColors(game.stateColor.darker());
                setActive(false);
            } else {
                setColors(game.stateColor);
            }
            setText(isDataRoot ? "" + (char) 20 : folder.name().replace('_', ' '), CENTER, font10);
            autoWidth();
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransferBrowse(game, crumbFolder, null, null, 0, "", "", 0));
        }
    }

    private class LeagueCrumbButton extends Button {

        LeagueCrumbButton() {
            setSize(0, 32);
            if (selectedTeam == null) {
                setColors(game.stateColor.darker());
                setActive(false);
            } else {
                setColors(game.stateColor);
            }
            setText(selectedLeague, CENTER, font10);
            autoWidth();
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, null, 0, "", "", 0));
        }
    }

    private class TeamCrumbLabel extends Button {

        TeamCrumbLabel() {
            setSize(0, 32);
            setColors(game.stateColor.darker());
            setActive(false);
            setText(selectedTeam.name, CENTER, font10);
            autoWidth();
        }
    }

    private class FolderButton extends Button {

        private final FileHandle targetFolder;

        FolderButton(FileHandle folder) {
            this.targetFolder = folder;
            setSize(340, 32);
            setColors(MenuTheme.ACTION);
            setText(folder.name().replace('_', ' '), CENTER, font14);
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransferBrowse(game, targetFolder, null, null, 0, "", "", 0));
        }
    }

    private class LeagueButton extends Button {

        LeagueButton(String league) {
            setSize(340, 32);
            setColors(MenuTheme.VALUE);
            setText(league, CENTER, font14);
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransferBrowse(game, folder, text, null, 0, "", "", 0));
        }
    }

    private class TeamButton extends Button {

        private final Team team;
        private final String leagueName;

        TeamButton(Team team, String leagueName) {
            this.team = team;
            this.leagueName = leagueName;
            setSize(270, 28);
            setColors(MenuTheme.ACTION);
            setText(team.name, CENTER, font14);
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransferBrowse(game, folder, leagueName, team, 0, "", "", 0));
        }
    }

    private class PlayerButton extends Button {

        private final TransferCandidate candidate;

        PlayerButton(TransferCandidate candidate, int y) {
            this.candidate = candidate;
            setGeometry((game.gui.WIDTH - 900) / 2, y, 900, 26);
            setColors(MenuTheme.VALUE);
            String text;
            if (candidateKey(candidate).equals(pendingOfferKey)) {
                text = "ACCEPT  " + candidate.player.shirtName + "  |  "
                        + candidate.team.name + "  |  " + formatMoney(pendingOfferPrice);
            } else {
                String price = game.settings.currency + " " + candidate.player.getPrice(game.settings.playerPriceFactor);
                text = candidate.player.shirtName + "  |  " + candidate.team.name + "  |  " + price;
            }
            setText(text, LEFT, font10);
        }

        @Override
        public void onFire1Down() {
            negotiate(candidate);
        }
    }

    private class PrevPlayerButton extends Button {

        private final int candidatesCount;

        PrevPlayerButton(int candidatesCount) {
            this.candidatesCount = candidatesCount;
            setGeometry(game.gui.WIDTH / 2 - 430, 616, 180, 36);
            setColors(MenuTheme.VALUE);
            setText("PREV", CENTER, font14);
        }

        @Override
        public void refresh() {
            setVisible(candidatesCount > PAGE_SIZE && page > 0);
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, selectedTeam, page - 1,
                    status, "", 0));
        }
    }

    private class NextPlayerButton extends Button {

        private final int candidatesCount;

        NextPlayerButton(int candidatesCount) {
            this.candidatesCount = candidatesCount;
            setGeometry(game.gui.WIDTH / 2 + 250, 616, 180, 36);
            setColors(MenuTheme.VALUE);
            setText("NEXT", CENTER, font14);
        }

        @Override
        public void refresh() {
            setVisible((page + 1) * PAGE_SIZE < candidatesCount);
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, selectedTeam, page + 1,
                    status, "", 0));
        }
    }

    private class AllPlayersButton extends Button {

        AllPlayersButton() {
            setGeometry(game.gui.WIDTH / 2 - 470, 660, 220, 36);
            setColors(MenuTheme.VALUE);
            setText("ALL PLAYERS", CENTER, font14);
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new ManagerTransfers(game));
        }
    }

    private class BackButton extends Button {

        BackButton() {
            setGeometry((game.gui.WIDTH - 180) / 2, 660, 180, 36);
            setColors(MenuTheme.ACTION);
            setText("BACK", CENTER, font14);
        }

        @Override
        public void onFire1Down() {
            if (selectedTeam != null) {
                game.setScreen(new ManagerTransferBrowse(game, folder, selectedLeague, null, 0, "", "", 0));
                return;
            }
            if (selectedLeague != null) {
                game.setScreen(new ManagerTransferBrowse(game, folder, null, null, 0, "", "", 0));
                return;
            }

            FileHandle root = getTransferRootFolder(game);
            if (!folder.equals(root) && !folder.equals(Assets.teamsRootFolder)) {
                game.setScreen(new ManagerTransferBrowse(game, folder.parent(), null, null, 0, "", "", 0));
            } else {
                game.setScreen(new PlayLeague(game));
            }
        }
    }

    private class ExitButton extends Button {

        ExitButton() {
            setGeometry(game.gui.WIDTH / 2 + 250, 660, 180, 36);
            setColors(MenuTheme.DANGER);
            setText(gettext("EXIT"), CENTER, font14);
        }

        @Override
        public void onFire1Down() {
            game.setScreen(new PlayLeague(game));
        }
    }

    private static class TransferCandidate {

        private final Team team;
        private final Player player;

        private TransferCandidate(Team team, Player player) {
            this.team = team;
            this.player = player;
        }
    }

    private static class TransferCandidateComparator implements Comparator<TransferCandidate> {

        @Override
        public int compare(TransferCandidate o1, TransferCandidate o2) {
            if (o1.player.getValue() != o2.player.getValue()) {
                return o2.player.getValue() - o1.player.getValue();
            }
            return o1.player.shirtName.compareTo(o2.player.shirtName);
        }
    }
}
