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.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;

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;

class ManagerTransfers extends GLScreen {

    private static final int PAGE_SIZE = 17;

    private final League league;
    private final Team managerTeam;
    private final ArrayList<TransferCandidate> candidates;
    private final int page;
    private final String status;
    private final String pendingOfferKey;
    private final double pendingOfferPrice;

    ManagerTransfers(GLGame game) {
        this(game, 0, "", "", 0);
    }

    private ManagerTransfers(GLGame game, int page, String status) {
        this(game, page, status, "", 0);
    }

    private ManagerTransfers(GLGame game, 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.candidates = buildCandidates();
        this.page = Math.max(0, Math.min(page, Math.max(0, (candidates.size() - 1) / PAGE_SIZE)));
        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);

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

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

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

        if (candidates.size() == 0) {
            w = new EmptyLabel();
            widgets.add(w);
        }

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

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

        w = new NextButton();
        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 ArrayList<TransferCandidate> buildCandidates() {
        ArrayList<TransferCandidate> list = new ArrayList<>();
        Set<String> seenTeams = new HashSet<>();
        for (Team team : league.teams) {
            if (team == managerTeam) {
                continue;
            }
            addTeamCandidates(list, seenTeams, team);
        }

        addFolderCandidates(list, seenTeams, getTransferRootFolder());

        Collections.sort(list, new TransferCandidateComparator());
        return list;
    }

    private void addFolderCandidates(ArrayList<TransferCandidate> list, Set<String> seenTeams, FileHandle folder) {
        for (FileHandle file : folder.list()) {
            if (file.isDirectory()) {
                addFolderCandidates(list, seenTeams, file);
            } else if (Assets.teamFilenameFilter.accept(null, file.name())) {
                Team team = Assets.json.fromJson(Team.class, file.readString("UTF-8"));
                team.path = normalizeTeamPath(Assets.getRelativeTeamPath(file));
                addTeamCandidates(list, seenTeams, team);
            }
        }
    }

    private void addTeamCandidates(ArrayList<TransferCandidate> list, Set<String> seenTeams, Team team) {
        if (team.type != Team.Type.CLUB) {
            return;
        }
        String path = normalizeTeamPath(team.path);
        if (path.length() > 0 && !seenTeams.add(path)) {
            return;
        }
        if (managerTeam.path != null && normalizeTeamPath(managerTeam.path).equals(path)) {
            return;
        }
        for (Player player : team.players) {
            if (!alreadyInManagerSquad(player)) {
                list.add(new TransferCandidate(team, player));
            }
        }
    }

    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 FileHandle getTransferRootFolder() {
        if (league.files == null || league.files.folder == null) {
            return Assets.teamsRootFolder;
        }

        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()));
        }

        return Assets.teamsRootFolder.child(folder);
    }

    private 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 void negotiate(TransferCandidate candidate) {
        if (managerTeam.players.size() >= Const.FULL_TEAM) {
            game.setScreen(new ManagerTransfers(game, 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 ManagerTransfers(game, page, text, key, askingPrice));
            return;
        }

        if (managerTeam.transferBudget < pendingOfferPrice) {
            String text = "NOT ENOUGH MONEY - NEED " + formatMoney(pendingOfferPrice)
                    + ", HAVE " + formatMoney(managerTeam.transferBudget);
            game.setScreen(new ManagerTransfers(game, 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 ManagerTransfers(game, 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 class HeaderLabel extends Label {

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

    private class StatusLabel extends Label {

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

    private class EmptyLabel extends Label {

        EmptyLabel() {
            setGeometry((game.gui.WIDTH - 960) / 2, 300, 960, 32);
            setText("NO PLAYERS AVAILABLE", CENTER, font14);
        }
    }

    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 PrevButton extends Button {

        PrevButton() {
            setGeometry(game.gui.WIDTH / 2 - 470, 660, 150, 36);
            setColors(MenuTheme.VALUE);
            setText("PREV", CENTER, font14);
        }

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

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

    private class BrowseButton extends Button {

        BrowseButton() {
            setGeometry(game.gui.WIDTH / 2 - 300, 660, 260, 36);
            setColors(MenuTheme.ACTION);
            setText("BROWSE TEAMS", CENTER, font14);
        }

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

    private class NextButton extends Button {

        NextButton() {
            setGeometry(game.gui.WIDTH / 2 + 320, 660, 150, 36);
            setColors(MenuTheme.VALUE);
            setText("NEXT", CENTER, font14);
        }

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

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

    private class ExitButton extends Button {

        ExitButton() {
            setGeometry(game.gui.WIDTH / 2 - 20, 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();
            }
            if (!o1.team.name.equals(o2.team.name)) {
                return o1.team.name.compareTo(o2.team.name);
            }
            return o1.player.shirtName.compareTo(o2.player.shirtName);
        }
    }
}
