package edu.whs.spin2018.baoapp.presenter;

import android.content.Intent;

import edu.whs.spin2018.baoapp.model.spiel.BaoSpiel;
import edu.whs.spin2018.baoapp.model.spiel.Position;
import edu.whs.spin2018.baoapp.model.remote.spielbrett.SpielbrettRemoteDataSource;
import edu.whs.spin2018.baoapp.model.spiel.Spielzug;
import edu.whs.spin2018.baoapp.model.spiel.TimerListener;
import edu.whs.spin2018.baoapp.model.spiel.spieler.ComputerSpielerEinfach;
import edu.whs.spin2018.baoapp.model.spiel.spieler.ComputerSpielerMittel;
import edu.whs.spin2018.baoapp.model.spiel.spieler.ComputerSpielerSchwer;
import edu.whs.spin2018.baoapp.model.spiel.spieler.MenschlicherSpieler;
import edu.whs.spin2018.baoapp.model.spiel.spieler.Spieler;
import edu.whs.spin2018.baoapp.model.spiel.spieler.SpielerIndex;
import edu.whs.spin2018.baoapp.service.Konstanten;
import edu.whs.spin2018.baoapp.views.spiel.BaoSpielContract;

public class BaoSpielPresenter implements BaoSpielContract.Presenter, TimerListener {

    public static final String SPIEL_TYP_EINZELSPIELER_LEICHT = "einzelspieler_leicht";
    public static final String SPIEL_TYP_EINZELSPIELER_MITTEL = "einzelspieler_mittel";
    public static final String SPIEL_TYP_EINZELSPIELER_SCHWER = "einzelspieler_schwer";
    public static final String SPIEL_TYP_MEHRSPIELER = "mehrspieler";
    public static final String SPIEL_TYP_LOKALES_SPIEL = "lokalesSpiel";
    private static final String TAG = "SpielbrettTag";
    private BaoSpiel baospiel;
    private BaoSpielContract.View view;
    private boolean aktionWirdAusgefuehrt;
    private String spielTyp;
    private String gewinnername;
    private String raum;
    private SpielbrettRemoteDataSource interactor;

    private String spielername;
    private String gegnername;

    /**
     * Stellt eine Schnittstelle zwischen BaoSpiel und BaoSpielActivity dar.
     *
     * @param view die Activity auf der alles angezeigt wird.
     */
    public BaoSpielPresenter(BaoSpielContract.View view, Intent spielinformationen) {
        this.view = view;
        initialisierePresenter(spielinformationen);
        view.setzePresenter(this);
    }

    /**
     * Der BaoSpielPresenter lädt Informationen zum aktuellen Spiel aus den @spielinformationen und
     * erstellt anhand dieser ein neues BaoSpiel.
     *
     * @param spielinformationen - Informationen ueber die Spieler
     */
    private void initialisierePresenter(Intent spielinformationen) {
        aktionWirdAusgefuehrt = false;
        spielername = spielinformationen.getStringExtra(Konstanten.EXTRA_SPIELER_NAME);
        gegnername = spielinformationen.getStringExtra(Konstanten.EXTRA_GEGNER_NAME);
        spielTyp = spielinformationen.getStringExtra(Konstanten.EXTRA_SPIELTYP);
        String spielerEinsUUID = spielinformationen.getStringExtra(Konstanten.EXTRA_UUID);
        raum = spielinformationen.getStringExtra(Konstanten.EXTRA_RAUM);
        String zeitTyp = spielinformationen.getStringExtra(Konstanten.EXTRA_SPIELMODUS);
        long spielzeit = ((spielinformationen.getIntExtra(Konstanten.EXTRA_SPIELZEIT_MINUTEN, 0)) * 60 * 1000)
                + ((spielinformationen.getIntExtra(Konstanten.EXTRA_SPIELZEIT_SEKUNDEN, 0)) * 1000);

        /* Ist die UUID von SpielerEins und der Raum identisch, so beginnt er das Spiel.
        Andernfalls beginnt SpielerZwei.*/
        SpielerIndex startenderSpieler = (spielTyp.equals(SPIEL_TYP_MEHRSPIELER) && !spielerEinsUUID.equals(raum))
                ? SpielerIndex.SPIELER_ZWEI : SpielerIndex.SPIELER_EINS;

        Spieler spielerEins = new MenschlicherSpieler(spielername, SpielerIndex.SPIELER_EINS);
        Spieler spielerZwei;
        switch (spielTyp) {
            case (SPIEL_TYP_EINZELSPIELER_LEICHT):
                spielerZwei = new ComputerSpielerEinfach(gegnername);
                break;
            case (SPIEL_TYP_EINZELSPIELER_MITTEL):
                spielerZwei = new ComputerSpielerMittel(gegnername);
                break;
            case (SPIEL_TYP_EINZELSPIELER_SCHWER):
                spielerZwei = new ComputerSpielerSchwer(gegnername);
                break;
            default:
                spielerZwei = new MenschlicherSpieler(gegnername, SpielerIndex.SPIELER_ZWEI);
                break;
        }

        //Die TimerAnzeigen in der View werden mit der Startzeit initialisiert.
        if (zeitTyp != null && !zeitTyp.equals(Konstanten.SPIELZEIT_OHNE_ZEIT)) {
            view.initialisiereTimerAnzeigen(spielzeit);
        }

        //Anhand des Index des startenden Spielers wird die richtige Timeranzeige gesetzt.
        view.setzeAktuelleTimerAnzeige(startenderSpieler);

        //Der Name des startenden Spielers wird hervorgehoben.
        view.zeigeAktuellenSpieler(startenderSpieler);

        baospiel = new BaoSpiel(this, spielerEins, spielerZwei, spielTyp, zeitTyp, spielzeit, startenderSpieler);

    }

    /**
     * Wird aufgerufen, wenn auf der View eine Mulde geklickt wurde.
     *
     * @param position die Position der Mulde die geklickt wurde
     */
    @Override
    public void onMuldenKlick(Position position) {

        if (!aktionWirdAusgefuehrt && spielTyp.equals(SPIEL_TYP_MEHRSPIELER)
                && position.gibZeile() >= 2
                && baospiel.gibAktuellenSpieler().gibSpielerIndex() == SpielerIndex.SPIELER_EINS) {

            baospiel.macheSpielzug(position);

            int umgerechneteSpalte = 7 - position.gibSpalte();
            int umgerechneteZeile = 3 - position.gibZeile();
            interactor.sendeSpielzug(new Position(umgerechneteZeile, umgerechneteSpalte), raum);

        } else if (!aktionWirdAusgefuehrt && (spielTyp.equals(BaoSpielPresenter.SPIEL_TYP_LOKALES_SPIEL))
                && baospiel.gibAktuellenSpieler().gibSpielerIndex().pruefeObPositionInSpielbereich(position)) {
            baospiel.macheSpielzug(position);

        } else if (!aktionWirdAusgefuehrt && position.gibZeile() >= 2
                && !spielTyp.equals(SPIEL_TYP_MEHRSPIELER)
                && !spielTyp.equals(SPIEL_TYP_LOKALES_SPIEL)) {
            baospiel.macheSpielzug(position);
        }
    }

    @Override
    public void onSpielzugAnzeigeAbgeschlossen() {
        aktionWirdAusgefuehrt = false;
        if (gewinnername != null) {
            view.zeigeGewinnerDialog(gewinnername);
        } else {
            baospiel.onAnimationEnde();
        }
    }

    @Override
    public void onTick(long uebrigeZeit) {
        view.zeigeUebrigeZeit(uebrigeZeit);
    }

    @Override
    public void onFinish() {
        String gewinnername = (baospiel.gibAktuellenSpieler().istSpielerEins())
                ? gegnername : spielername;
        view.zeigeGewinnerDialog(gewinnername);
    }

    @Override
    public void onTimerStart() {
        //Wird nicht verwendet
    }

    @Override
    public void initialisiereAktuelleTimeranzeige(SpielerIndex spielerIndex) {
        view.setzeAktuelleTimerAnzeige(spielerIndex);
    }

    @Override
    public void verarbeiteSpielerwechsel(SpielerIndex aktuellerSpielerIndex) {
        view.zeigeAktuellenSpieler(aktuellerSpielerIndex);
    }

    @Override
    public void verarbeiteSpielzug(Spielzug spielzug) {
        aktionWirdAusgefuehrt = true;

        if (spielzug.gibGewinnerName() != null) {
            gewinnername = spielzug.gibGewinnerName();
        }
        view.aktualisiereMuldenAnzeige(spielzug);
    }

    @Override
    public void stop() {
        baospiel.beendeTimer();
        interactor.entferneRegistrierteListener();
        interactor.raumVerlassen(raum);
    }

    @Override
    public void setzeServiceInteractor(SpielbrettRemoteDataSource interactor) {
        this.interactor = interactor;
        this.interactor.setzeListener(this);
    }

    @Override
    public void onBenutzerVerlaesstRaum() {
        interactor.raumVerlassen(raum);
        view.zeigeGewinnerDialog(spielername);
    }

    @Override
    public void onSpielzugErhalten(Position position) {
        onRemoteMuldenKlick(position);
    }

    /**
     * Wird aufgerufen, wenn der Spielzug vom Gegner erhalten wird.
     *
     * @param pos - Position, die der Gegner geklickt hat.
     */
    private void onRemoteMuldenKlick(Position pos) {
        baospiel.macheSpielzug(pos);
    }
}
