package io.github.lonamiwebs.klooni.game;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.utils.Align;

import io.github.lonamiwebs.klooni.Klooni;
import io.github.lonamiwebs.klooni.SkinLoader;
import io.github.lonamiwebs.klooni.serializer.BinSerializable;

public abstract class BaseScorer implements BinSerializable {

    //region Members

    protected int currentScore;

    final Label currentScoreLabel;
    final Label highScoreLabel;

    final Texture cupTexture;
    final Rectangle cupArea;

    private final Color cupColor;

    // To interpolate between shown score -> real score
    private float shownScore;

    //endregion

    //region Constructor

    // The board size is required when calculating the score
    BaseScorer(final Klooni game, GameLayout layout, int highScore) {
        cupTexture = SkinLoader.loadPng("cup.png");
        cupColor = Klooni.theme.currentScore.cpy();
        cupArea = new Rectangle();

        Label.LabelStyle labelStyle = new Label.LabelStyle();
        labelStyle.font = game.skin.getFont("font");

        currentScoreLabel = new Label("0", labelStyle);
        currentScoreLabel.setAlignment(Align.right);

        highScoreLabel = new Label(Integer.toString(highScore), labelStyle);

        layout.update(this);
    }

    //endregion

    //region Private methods

    // The original game seems to work as follows:
    // If < 1 were cleared, score = 0
    // If = 1  was cleared, score = cells cleared
    // If > 1 were cleared, score = cells cleared + score(cleared - 1)
    final int calculateClearScore(int stripsCleared, int boardSize) {
        if (stripsCleared < 1) return 0;
        if (stripsCleared == 1) return boardSize;
        else return boardSize * stripsCleared + calculateClearScore(stripsCleared - 1, boardSize);
    }

    //endregion

    //region Public methods

    // Adds the score a given piece would give
    public int addPieceScore(int areaPut) {
        currentScore += areaPut;
        return areaPut;
    }

    // Adds the score given by the board, this is, the count of cleared strips
    public int addBoardScore(int stripsCleared, int boardSize) {
        int score = calculateClearScore(stripsCleared, boardSize);
        currentScore += score;
        return score;
    }

    public int getCurrentScore() {
        return currentScore;
    }

    public void pause() { }
    public void resume() { }

    abstract public boolean isGameOver();
    abstract protected boolean isNewRecord();

    public String gameOverReason() { return ""; }

    abstract public void saveScore();

    public void draw(SpriteBatch batch) {
        // If we beat a new record, the cup color will linear interpolate to the high score color
        cupColor.lerp(isNewRecord() ? Klooni.theme.highScore : Klooni.theme.currentScore, 0.05f);
        batch.setColor(cupColor);
        batch.draw(cupTexture, cupArea.x, cupArea.y, cupArea.width, cupArea.height);

        int roundShown = MathUtils.round(shownScore);
        if (roundShown != currentScore) {
            shownScore = Interpolation.linear.apply(shownScore, currentScore, 0.1f);
            currentScoreLabel.setText(Integer.toString(MathUtils.round(shownScore)));
        }

        currentScoreLabel.setColor(Klooni.theme.currentScore);
        currentScoreLabel.draw(batch, 1f);

        highScoreLabel.setColor(Klooni.theme.highScore);
        highScoreLabel.draw(batch, 1f);
    }

    //endregion
}
