package com.elifut.activity;

import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.elifut.BuildConfig;
import com.elifut.R;
import com.elifut.ResponseObserver;
import com.elifut.match.MatchResultController;
import com.elifut.models.Club;
import com.elifut.models.Goal;
import com.elifut.models.LeagueRound;
import com.elifut.models.Match;
import com.elifut.models.MatchResult;
import com.elifut.preferences.LeagueDetails;
import com.elifut.preferences.UserPreferences;
import com.github.rahatarmanahmed.cpv.CircularProgressView;
import com.squareup.picasso.Picasso;

import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import butterknife.BindDimen;
import butterknife.BindString;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import icepick.State;
import rx.Observable;
import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.subscriptions.CompositeSubscription;

public class MatchProgressActivity extends ElifutActivity {
  private static final String TAG = MatchProgressActivity.class.getSimpleName();
  private static final String EXTRA_ROUND = "EXTRA_ROUND";
  private static final int MIN_GAME_SPEED = 1;
  private static final int MAX_GAME_SPEED = 4;

  @BindView(R.id.toolbar) Toolbar toolbar;
  @BindView(R.id.img_team_home) ImageView imgTeamHome;
  @BindView(R.id.img_team_away) ImageView imgTeamAway;
  @BindView(R.id.txt_team_home) TextView txtTeamHome;
  @BindView(R.id.txt_team_away) TextView txtTeamAway;
  @BindView(R.id.txt_team_home_goals) TextView txtTeamHomeGoals;
  @BindView(R.id.events_layout) LinearLayout eventsLayout;
  @BindView(R.id.events_timeline) View eventsTimeline;
  @BindView(R.id.events_scrollview) ScrollView eventsScrollView;
  @BindView(R.id.txt_team_away_goals) TextView txtTeamAwayGoals;
  @BindView(R.id.progress_view) CircularProgressView fractionView;
  @BindView(R.id.fab_play_pause) FloatingActionButton playPauseButton;
  @BindView(R.id.fab_fast_forward) FloatingActionButton fastForwardButton;
  @BindView(R.id.fab_backward) FloatingActionButton backwardButton;
  @BindView(R.id.fab_done) FloatingActionButton doneButton;
  @BindView(R.id.fab_container) LinearLayout fabContainer;
  @BindString(R.string.end_first_half) String strEndOfFirstHalf;
  @BindString(R.string.end_match) String strEndOfMatch;
  @BindDimen(R.dimen.match_event_icon_size) int iconSize;
  @BindDimen(R.dimen.match_event_icon_padding) int iconPadding;

  @Inject UserPreferences userPreferences;
  @Inject LeagueDetails leagueDetails;

  @State LeagueRound round;
  @State boolean isRunning;
  @State int elapsedMinutes;

  private final CompositeSubscription subscriptions = new CompositeSubscription();
  private String finalScoreMessage;
  private int finalScoreIcon;
  private Match match;
  private Club userClub;
  private MatchResult matchResult;
  private final Observer<Club> clubObserver =
      new ResponseObserver<Club>(this, TAG, "Failed to load club") {
        @Override public void onNext(Club response) {
          ImageView imgView;
          TextView txtView;
          if (response.nameEquals(match.home())) {
            imgView = imgTeamHome;
            txtView = txtTeamHome;
          } else {
            imgView = imgTeamAway;
            txtView = txtTeamAway;
          }
          Picasso.with(MatchProgressActivity.this)
              .load(response.large_image())
              .into(imgView);

          txtView.setText(response.shortName());
        }

        @Override public void onCompleted() {
          if (!matchResult.isDraw()) {
            Club winner = matchResult.winner();
            //noinspection ConstantConditions
            boolean isWinner = winner.nameEquals(userClub);
            finalScoreIcon = isWinner ? R.drawable.ic_mood_black_48px
                : R.drawable.ic_sentiment_very_dissatisfied_black_48px;
            if (isWinner) {
              finalScoreMessage = getString(R.string.winner);
            } else {
              finalScoreMessage = getString(R.string.defeated);
            }
          } else {
            finalScoreIcon = R.drawable.ic_sentiment_neutral_black_48px;
            finalScoreMessage = getString(R.string.draw);
          }
          if (BuildConfig.DEBUG) {
            Log.d(TAG, finalScoreMessage + " Final score is " + matchResult.finalScore());
          }

          startTimer();
        }
      };

  public static Intent newIntent(Context context, LeagueRound round) {
    return new Intent(context, MatchProgressActivity.class)
        .putExtra(EXTRA_ROUND, round);
  }

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
    setContentView(R.layout.activity_match_progress);
    ButterKnife.bind(this);
    daggerComponent().inject(this);
    setSupportActionBar(toolbar);
    if (savedInstanceState == null) {
      Intent intent = getIntent();
      round = intent.getParcelableExtra(EXTRA_ROUND);
    }
    userClub = userPreferences.club();
    match = round.findMatchByClub(userClub);
    matchResult = match.result();
    //noinspection ConstantConditions
    getSupportActionBar().setTitle(getString(R.string.round_x_match, round.roundNumber()));
    setGameSpeed(userPreferences.gameSpeed());
    fractionView.setMaxProgress(45);
    loadClubs(match.home().id(), match.away().id());
  }

  @Override protected void onDestroy() {
    super.onDestroy();
    stopTimer();
    MatchResultController controller = new MatchResultController(userPreferences);
    controller.updateWithResult(matchResult);
  }

  private void loadClubs(int homeId, int awayId) {
    subscriptions.add(clubObservable(homeId)
        .mergeWith(clubObservable(awayId))
        .subscribe(clubObserver));
  }

  private Observable<Club> clubObservable(int id) {
    return service.club(id).compose(this.<Club>applyTransformations());
  }

  private void stopTimer() {
    subscriptions.clear();
    isRunning = false;
  }

  private void startTimer() {
    subscriptions.add(matchResult.eventsObservable(elapsedMinutes, userPreferences.gameSpeed())
        .map(matchEvent -> (Goal) matchEvent)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(goal -> {
          boolean isHomeGoal = goal.club().nameEquals(match.home());
          TextView txtScore = isHomeGoal ? txtTeamHomeGoals : txtTeamAwayGoals;
          int currGoals = Integer.parseInt(txtScore.getText().toString());
          txtScore.setText(String.valueOf(++currGoals));
          int gravity = isHomeGoal ? GravityCompat.START : GravityCompat.END;
          appendEvent(R.drawable.ball, goal.time() + "' " + goal.player().name(), gravity);
        }));

    subscriptions.add(timerObservable()
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(l -> {
          elapsedMinutes++;
          fractionView.setProgress(elapsedMinutes % 45);
          if (elapsedMinutes == 45) {
            appendEvent(R.drawable.ic_schedule_black_48px, strEndOfFirstHalf, Gravity.CENTER);
          } else if (elapsedMinutes == 90) {
            stopTimer();
            appendEvent(R.drawable.ic_schedule_black_48px, strEndOfMatch, Gravity.CENTER);
            appendEvent(finalScoreIcon, finalScoreMessage, Gravity.CENTER);
            Club winner = matchResult.winner();
            boolean isDraw = matchResult.isDraw();
            boolean isWinner = !isDraw && userClub.nameEquals(winner);
            if (isDraw || isWinner) {
              appendEvent(R.drawable.ic_attach_money_black_24dp, "+" +
                      (isWinner ? UserPreferences.COINS_PRIZE_WIN : UserPreferences
                          .COINS_PRIZE_DRAW),
                  Gravity.CENTER_HORIZONTAL);
            }
            playPauseButton.setVisibility(View.GONE);
            backwardButton.setVisibility(View.GONE);
            fastForwardButton.setVisibility(View.GONE);
            doneButton.setVisibility(View.VISIBLE);
            fractionView.setProgress(45);
          }
        }));
    isRunning = true;
  }

  @NonNull private Observable<Long> timerObservable() {
    return Observable.interval(0, 1000 / userPreferences.gameSpeed(), TimeUnit.MILLISECONDS);
  }

  private void appendEvent(@DrawableRes int icon, String text, int gravity) {
    FrameLayout view = (FrameLayout) LayoutInflater.from(this)
        .inflate(R.layout.match_event, eventsLayout, false);
    TextView textView = view.findViewById(R.id.txt_match_events);
    textView.setText(text);
    Drawable drawable = ContextCompat.getDrawable(this, icon);
    drawable.setBounds(0, 0, iconSize, iconSize);
    textView.setCompoundDrawablePadding(iconPadding);
    if (gravity == GravityCompat.START) {
      textView.setCompoundDrawables(null, null, drawable, null);
    } else {
      textView.setCompoundDrawables(drawable, null, null, null);
    }
    LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams();
    layoutParams.gravity = gravity;
    view.setLayoutParams(layoutParams);
    textView.setGravity(gravity);
    eventsLayout.addView(view, 0);
    eventsTimeline.setVisibility(View.VISIBLE);
    eventsScrollView.smoothScrollTo(0, 0);
  }

  private void setGameSpeed(int gameSpeed) {
    if (userPreferences.gameSpeed() != gameSpeed) {
      userPreferences.gameSpeedPreference().set(gameSpeed);
      stopTimer();
      startTimer();
    }
    Drawable slowerBtnBg = backwardButton.getBackground();
    Drawable fasterBtnBg = fastForwardButton.getBackground();
    slowerBtnBg.setColorFilter(null);
    backwardButton.setClickable(true);
    fasterBtnBg.setColorFilter(null);
    fastForwardButton.setClickable(true);
    if (gameSpeed == MIN_GAME_SPEED) {
      slowerBtnBg.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
      backwardButton.setClickable(false);
    } else if (gameSpeed == MAX_GAME_SPEED) {
      fasterBtnBg.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
      fastForwardButton.setClickable(false);
    }
  }

  @OnClick(R.id.fab_backward) void onBackward() {
    int currSpeed = userPreferences.gameSpeed();
    currSpeed /= 2;
    setGameSpeed(Math.max(MIN_GAME_SPEED, currSpeed));
  }

  @OnClick(R.id.fab_fast_forward) void onFastForward() {
    int currSpeed = userPreferences.gameSpeed();
    currSpeed *= 2;
    setGameSpeed(Math.min(MAX_GAME_SPEED, currSpeed));
  }

  @OnClick(R.id.fab_play_pause) void onClickPause() {
    if (isRunning) {
      stopTimer();
      Snackbar.make(fabContainer, R.string.match_paused, Snackbar.LENGTH_SHORT).show();
      playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_48dp);
    } else {
      startTimer();
      Snackbar.make(fabContainer, R.string.match_resumed, Snackbar.LENGTH_SHORT).show();
      playPauseButton.setImageResource(R.drawable.ic_pause_white_48dp);
    }
  }

  @OnClick(R.id.fab_done) void onClickDone() {
    finish();
    startActivity(LeagueRoundResultsActivity.newIntent(this, round));
  }
}