/*
 * Copyright 2016, The Android Open Source Project
 * Copyright (c) 2017-2018 Spotify AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.android.architecture.blueprints.todoapp.tasks.view;

import static com.example.android.architecture.blueprints.todoapp.tasks.domain.TasksListEvent.navigateToTaskDetailsRequested;
import static com.example.android.architecture.blueprints.todoapp.tasks.domain.TasksListEvent.newTaskClicked;
import static com.example.android.architecture.blueprints.todoapp.tasks.domain.TasksListEvent.refreshRequested;
import static com.example.android.architecture.blueprints.todoapp.tasks.domain.TasksListEvent.taskMarkedActive;
import static com.example.android.architecture.blueprints.todoapp.tasks.domain.TasksListEvent.taskMarkedComplete;

import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.example.android.architecture.blueprints.todoapp.R;
import com.example.android.architecture.blueprints.todoapp.tasks.domain.TasksListEvent;
import com.example.android.architecture.blueprints.todoapp.tasks.view.TasksListViewData.TaskViewData;
import com.google.common.collect.ImmutableList;
import com.spotify.mobius.Connectable;
import com.spotify.mobius.Connection;
import com.spotify.mobius.functions.Consumer;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import javax.annotation.Nonnull;

public class TasksViews
    implements TasksListViewActions, Connectable<TasksListViewData, TasksListEvent> {
  private final View mRoot;
  private final ScrollChildSwipeRefreshLayout mSwipeRefreshLayout;
  private final FloatingActionButton mFab;
  private final Observable<TasksListEvent> menuEvents;

  private TasksAdapter mListAdapter;

  private View mNoTasksView;

  private ImageView mNoTaskIcon;

  private TextView mNoTaskMainView;

  private TextView mNoTaskAddView;

  private LinearLayout mTasksView;

  private TextView mFilteringLabelView;

  public TasksViews(
      LayoutInflater inflater,
      ViewGroup parent,
      FloatingActionButton fab,
      Observable<TasksListEvent> menuEvents) {
    this.menuEvents = menuEvents;
    mRoot = inflater.inflate(R.layout.tasks_frag, parent, false);
    mListAdapter = new TasksAdapter();
    // Set up allTasks view
    ListView listView = mRoot.findViewById(R.id.tasks_list);
    listView.setAdapter(mListAdapter);
    mFilteringLabelView = mRoot.findViewById(R.id.filteringLabel);
    mTasksView = mRoot.findViewById(R.id.tasksLL);

    // Set up  no allTasks view
    mNoTasksView = mRoot.findViewById(R.id.noTasks);
    mNoTaskIcon = mRoot.findViewById(R.id.noTasksIcon);
    mNoTaskMainView = mRoot.findViewById(R.id.noTasksMain);
    mNoTaskAddView = mRoot.findViewById(R.id.noTasksAdd);
    fab.setImageResource(R.drawable.ic_add);
    mFab = fab;
    // Set up progress indicator
    mSwipeRefreshLayout = mRoot.findViewById(R.id.refresh_layout);
    mSwipeRefreshLayout.setColorSchemeColors(
        ContextCompat.getColor(mRoot.getContext(), R.color.colorPrimary),
        ContextCompat.getColor(mRoot.getContext(), R.color.colorAccent),
        ContextCompat.getColor(mRoot.getContext(), R.color.colorPrimaryDark));
    // Set the scrolling view in the custom SwipeRefreshLayout.
    mSwipeRefreshLayout.setScrollUpChild(listView);
  }

  public View getRootView() {
    return mRoot;
  }

  @Override
  public void showSuccessfullySavedMessage() {
    showMessage(R.string.successfully_saved_task_message);
  }

  @Override
  public void showTaskMarkedComplete() {
    showMessage(R.string.task_marked_complete);
  }

  @Override
  public void showTaskMarkedActive() {
    showMessage(R.string.task_marked_active);
  }

  @Override
  public void showCompletedTasksCleared() {
    showMessage(R.string.completed_tasks_cleared);
  }

  @Override
  public void showLoadingTasksError() {
    showMessage(R.string.loading_tasks_error);
  }

  private void showMessage(int messageRes) {
    Snackbar.make(mRoot, messageRes, Snackbar.LENGTH_LONG).show();
  }

  @Nonnull
  @Override
  public Connection<TasksListViewData> connect(Consumer<TasksListEvent> output) {

    addUiListeners(output);
    Disposable disposable = menuEvents.subscribe(output::accept);

    return new Connection<TasksListViewData>() {
      @Override
      public void accept(TasksListViewData value) {
        render(value);
      }

      @Override
      public void dispose() {
        disposable.dispose();
        mNoTaskAddView.setOnClickListener(null);
        mFab.setOnClickListener(null);
        mSwipeRefreshLayout.setOnRefreshListener(null);
        mListAdapter.setItemListener(null);
      }
    };
  }

  private void addUiListeners(Consumer<TasksListEvent> output) {
    mNoTaskAddView.setOnClickListener(__ -> output.accept(newTaskClicked()));
    mFab.setOnClickListener(__ -> output.accept(newTaskClicked()));
    mSwipeRefreshLayout.setOnRefreshListener(() -> output.accept(refreshRequested()));
    mListAdapter.setItemListener(
        new TasksAdapter.TaskItemListener() {
          @Override
          public void onTaskClick(String id) {
            output.accept(navigateToTaskDetailsRequested(id));
          }

          @Override
          public void onCompleteTaskClick(String id) {
            output.accept(taskMarkedComplete(id));
          }

          @Override
          public void onActivateTaskClick(String id) {
            output.accept(taskMarkedActive(id));
          }
        });
  }

  private void showEmptyTaskState(TasksListViewData.EmptyTasksViewData vd) {
    mTasksView.setVisibility(View.GONE);
    mNoTasksView.setVisibility(View.VISIBLE);

    mNoTaskMainView.setText(vd.title());
    mNoTaskIcon.setImageResource(vd.icon());
    mNoTaskAddView.setVisibility(vd.addViewVisibility());
  }

  private void showNoTasksViewState() {
    mTasksView.setVisibility(View.GONE);
    mNoTasksView.setVisibility(View.GONE);
  }

  private void showTasks(ImmutableList<TaskViewData> tasks) {
    mListAdapter.replaceData(tasks);

    mTasksView.setVisibility(View.VISIBLE);
    mNoTasksView.setVisibility(View.GONE);
  }

  private void render(TasksListViewData value) {
    // Make sure setRefreshing() is called after the layout is done with everything else.
    mSwipeRefreshLayout.setRefreshing(value.loading());
    mFilteringLabelView.setText(value.filterLabel());
    value
        .viewState()
        .match(
            awaitingTasks -> showNoTasksViewState(),
            emptyTasks -> showEmptyTaskState(emptyTasks.viewData()),
            hasTasks -> showTasks(hasTasks.taskViewData()));
  }
}