package org.thosp.yourlocalweather;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.graphics.Canvas;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.speech.tts.TextToSpeech;
import android.support.annotation.Nullable;
import android.support.v4.app.NavUtils;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import org.thosp.yourlocalweather.model.VoiceSettingParametersDbHelper;
import org.thosp.yourlocalweather.utils.AppPreference;
import org.thosp.yourlocalweather.utils.PreferenceUtil;
import org.thosp.yourlocalweather.utils.TimeUtils;
import org.thosp.yourlocalweather.utils.Utils;
import org.thosp.yourlocalweather.utils.VoiceSettingParamType;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import static org.thosp.yourlocalweather.utils.LogToFile.appendLog;

public class VoiceSettingsActivity extends BaseActivity {

    public static final String TAG = "VoiceSettingsActivity";

    private VoiceSettingsAdapter voiceSettingsAdapter;
    private RecyclerView recyclerView;
    private VoiceSettingParametersDbHelper voiceSettingParametersDbHelper;
    private Locale applicationLocale;
    private TextToSpeech tts;

    Handler timerHandler = new Handler();
    Runnable timerRunnable = new Runnable() {
        @Override
        public void run() {
            if (tts == null) {
                return;
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Set<Locale> ttsAvailableLanguages = tts.getAvailableLanguages();
                processTtsLanguages(ttsAvailableLanguages);
            }
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ((YourLocalWeather) getApplication()).applyTheme(this);
        super.onCreate(savedInstanceState);
        applicationLocale = new Locale(PreferenceUtil.getLanguage(this));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
        }
        setContentView(R.layout.activity_voice_settings);

        setupActionBar();
        setupRecyclerView();
        voiceSettingParametersDbHelper = VoiceSettingParametersDbHelper.getInstance(this);
    }

    @Override
    public void onResume(){
        super.onResume();
        checkLanguageCompatibility();
        voiceSettingsAdapter = new VoiceSettingsAdapter(voiceSettingParametersDbHelper.getAllSettingIds());
        recyclerView.setAdapter(voiceSettingsAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.voice_settings_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_voice_settings_language:
                startActivity(new Intent(VoiceSettingsActivity.this, VoiceLanguageOptionsActivity.class));
                return true;
            case android.R.id.home:
                NavUtils.navigateUpFromSameTask(this);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public synchronized void addVoiceSetting(View view) {
        long newVoiceSettingId;
        if ((voiceSettingsAdapter.voiceSettingIds == null) || voiceSettingsAdapter.voiceSettingIds.isEmpty()) {
            newVoiceSettingId = 1;
        } else {
            newVoiceSettingId = Collections.max(voiceSettingsAdapter.voiceSettingIds) + 1;
        }
        voiceSettingParametersDbHelper.saveLongParam(
                newVoiceSettingId,
                VoiceSettingParamType.VOICE_SETTING_TRIGGER_TYPE.getVoiceSettingParamTypeId(),
                0);
        voiceSettingParametersDbHelper.saveBooleanParam(
                newVoiceSettingId,
                VoiceSettingParamType.VOICE_SETTING_LOCATIONS.getVoiceSettingParamTypeId(),
                true);
        voiceSettingParametersDbHelper.saveLongParam(
                newVoiceSettingId,
                VoiceSettingParamType.VOICE_SETTING_ENABLED_VOICE_DEVICES.getVoiceSettingParamTypeId(),
                7);
        voiceSettingParametersDbHelper.saveBooleanParam(
                newVoiceSettingId,
                VoiceSettingParamType.VOICE_SETTING_ENABLED_WHEN_BT_DEVICES.getVoiceSettingParamTypeId(),
                true);
        voiceSettingParametersDbHelper.saveLongParam(
                newVoiceSettingId,
                VoiceSettingParamType.VOICE_SETTING_PARTS_TO_SAY.getVoiceSettingParamTypeId(),
                325);
        voiceSettingParametersDbHelper.saveLongParam(
                newVoiceSettingId,
                VoiceSettingParamType.VOICE_SETTING_TRIGGER_DAY_IN_WEEK.getVoiceSettingParamTypeId(),
                127);
        voiceSettingParametersDbHelper.saveBooleanParam(
                newVoiceSettingId,
                VoiceSettingParamType.VOICE_SETTING_TRIGGER_ENABLED_BT_DEVICES.getVoiceSettingParamTypeId(),
                true);
        moveToAddVoiceSettingsActivity(newVoiceSettingId);
    }

    private void moveToAddVoiceSettingsActivity(long newVoiceSettingId) {
        Intent intent = new Intent(VoiceSettingsActivity.this, AddVoiceSettingActivity.class);
        intent.putExtra("voiceSettingId", newVoiceSettingId);
        startActivity(intent);
    }

    private void setupActionBar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
    }

    private void checkLanguageCompatibility() {
        if (tts != null) {
            checkTtsLanguages();
            return;
        }
        TextToSpeech.OnInitListener onInitListener = new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                appendLog(getBaseContext(), TAG, "TextToSpeech initialized with status: " + status);
                if ((tts != null) && (status == TextToSpeech.SUCCESS)) {
                    checkTtsLanguages();
                }
            }
        };
        tts = new TextToSpeech(getBaseContext(), onInitListener);
    }

    private void checkTtsLanguages() {
        Set<Locale> ttsAvailableLanguages;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ttsAvailableLanguages = tts.getAvailableLanguages();
            if (ttsAvailableLanguages.isEmpty()) {
                timerHandler.postDelayed(timerRunnable, 1000);
                return;
            }
        } else {
            ttsAvailableLanguages = new HashSet<>();
            Locale[] locales = Locale.getAvailableLocales();
            for (Locale loc : locales) {
                if (!loc.toString().toLowerCase().contains("os")
                        && tts.isLanguageAvailable(loc) >= 0) {
                    ttsAvailableLanguages.add(loc);
                }
            }
        }
        processTtsLanguages(ttsAvailableLanguages);
    }

    private void processTtsLanguages(Set<Locale> ttsAvailableLanguages) {
        boolean supportedLanguage = false;
        appendLog(getBaseContext(), TAG, "Locales:ttsAvailableLanguages: " + ttsAvailableLanguages + ":" + ((ttsAvailableLanguages != null) ? ttsAvailableLanguages.size() : ""));
        for (Locale locale : ttsAvailableLanguages) {
            appendLog(getBaseContext(), TAG, "Locales: ", locale.getISO3Language(), ":", applicationLocale.getISO3Language());
            if (locale.getISO3Language().equals(applicationLocale.getISO3Language())) {
                supportedLanguage = true;
            }
        }
        if (!supportedLanguage) {
            int duration = Toast.LENGTH_LONG;
            Toast toast = Toast.makeText(getBaseContext(), getString(R.string.pref_title_tts_not_supported), duration);
            toast.show();
        }
    }

    private void setupRecyclerView() {
        recyclerView = findViewById(R.id.voice_setting_recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(VoiceSettingsActivity.this));

        final VoiceSettingsSwipeController swipeController = new VoiceSettingsSwipeController(new LocationsSwipeControllerActions() {
            @Override
            public void onRightClicked(int position) {
                deleteVoiceSetting(position);
            }

            @Override
            public void onLeftClicked(int position) {
                moveToAddVoiceSettingsActivity(voiceSettingsAdapter.voiceSettingIds.get(position));
            }
        }, this);

        ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeController);

        recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
            @Override
            public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
                swipeController.onDraw(c);
            }
        });

        itemTouchhelper.attachToRecyclerView(recyclerView);
    }

    private void deleteVoiceSetting(int position) {
        Long voiceSettingId = voiceSettingsAdapter.voiceSettingIds.get(position);
        voiceSettingParametersDbHelper.deleteAllSettings(voiceSettingId);
        voiceSettingsAdapter.voiceSettingIds.remove(position);
        voiceSettingsAdapter.notifyItemRemoved(position);
        voiceSettingsAdapter.notifyItemRangeChanged(position, voiceSettingsAdapter.getItemCount());
        List<Long> voiceSettingIds = voiceSettingParametersDbHelper.getAllSettingIds();
        voiceSettingsAdapter = new VoiceSettingsAdapter(voiceSettingIds);
        recyclerView.setAdapter(voiceSettingsAdapter);
        TimeUtils.setupAlarmForVoice(getBaseContext());
    }

    @Override
    protected void updateUI() {
    }

    public class VoiceSettingHolder extends RecyclerView.ViewHolder {

        private Long voiceSettingId;
        private TextView voiceSettingIdView;
        private TextView voiceSettingTypeView;
        private TextView voiceSettingAddInfo1View;
        private TextView voiceSettingAddInfo2View;

        VoiceSettingHolder(View itemView) {
            super(itemView);
            voiceSettingIdView = itemView.findViewById(R.id.voice_setting_id);
            voiceSettingTypeView = itemView.findViewById(R.id.voice_setting_type);
            voiceSettingAddInfo1View = itemView.findViewById(R.id.voice_setting_add_info_1);
            voiceSettingAddInfo2View = itemView.findViewById(R.id.voice_setting_add_info_2);

        }

        void bindVoiceSetting(Long voiceSettingId) {
            this.voiceSettingId = voiceSettingId;
            if (voiceSettingId == null) {
                return;
            }
            Long triggerType = voiceSettingParametersDbHelper.getLongParam(
                    voiceSettingId,
                    VoiceSettingParamType.VOICE_SETTING_TRIGGER_TYPE.getVoiceSettingParamTypeId());
            voiceSettingIdView.setText(getString(R.string.pref_title_tts_trigger_type_label));
            if (triggerType != null) {
                String triggerTypeName = "";
                String addInfo1 = "";
                String addInfo2 = "";
                BluetoothAdapter bluetoothAdapter = Utils.getBluetoothAdapter(getBaseContext());
                Set<BluetoothDevice> bluetoothDeviceSet;
                if (bluetoothAdapter != null) {
                    bluetoothDeviceSet = bluetoothAdapter.getBondedDevices();
                } else {
                    bluetoothDeviceSet = new HashSet<>();
                }
                if (triggerType == 0) {
                    triggerTypeName = getString(R.string.voice_setting_trigger_on_weather_update);

                    StringBuilder addInfo1Builder = new StringBuilder();
                    Long enabledVoiceDevices = voiceSettingParametersDbHelper.getLongParam(
                            voiceSettingId,
                            VoiceSettingParamType.VOICE_SETTING_ENABLED_VOICE_DEVICES.getVoiceSettingParamTypeId());
                    boolean isNotFirst = false;
                    if (enabledVoiceDevices != null) {
                        if (TimeUtils.isCurrentSettingIndex(enabledVoiceDevices, 2)) {
                            addInfo1Builder.append(getString(R.string.pref_title_tts_speaker_label));
                            isNotFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(enabledVoiceDevices, 1)) {
                            if (isNotFirst) {
                                addInfo1Builder.append(", ");
                            }
                            addInfo1Builder.append(getString(R.string.pref_title_tts_wired_headset_label));
                            isNotFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(enabledVoiceDevices, 0)) {
                            if (isNotFirst) {
                                addInfo1Builder.append(", ");
                            }
                            addInfo1Builder.append(getString(R.string.pref_title_tts_bt_label));
                            addInfo1Builder.append(": ");
                        }

                        Boolean enabledBtVoiceDevices = voiceSettingParametersDbHelper.getBooleanParam(
                                voiceSettingId,
                                VoiceSettingParamType.VOICE_SETTING_ENABLED_WHEN_BT_DEVICES.getVoiceSettingParamTypeId());
                        if ((enabledBtVoiceDevices != null) && enabledBtVoiceDevices) {
                            addInfo1Builder.append(getString(R.string.pref_title_tts_bt_all));
                        } else {
                            String btDevices = voiceSettingParametersDbHelper.getStringParam(
                                    voiceSettingId,
                                    VoiceSettingParamType.VOICE_SETTING_ENABLED_WHEN_BT_DEVICES.getVoiceSettingParamTypeId());
                            boolean notFirst = false;
                            for(BluetoothDevice bluetoothDevice: bluetoothDeviceSet) {
                                String currentDeviceName = bluetoothDevice.getName();
                                String currentDeviceAddress = bluetoothDevice.getAddress();
                                if (btDevices.contains(currentDeviceAddress)) {
                                    if (notFirst) {
                                        addInfo1Builder.append(", ");
                                    }
                                    addInfo1Builder.append(currentDeviceName);
                                    notFirst = true;
                                }
                            }
                        }
                        addInfo1 = addInfo1Builder.toString();
                    }
                } else if (triggerType == 1) {
                    triggerTypeName = getString(R.string.voice_setting_trigger_when_bt_connected);

                    Boolean enabledVoiceDevices = voiceSettingParametersDbHelper.getBooleanParam(
                            voiceSettingId,
                            VoiceSettingParamType.VOICE_SETTING_TRIGGER_ENABLED_BT_DEVICES.getVoiceSettingParamTypeId());
                    if ((enabledVoiceDevices != null) && enabledVoiceDevices) {
                        addInfo1 = getString(R.string.pref_title_tts_bt_all);
                    } else {
                        String btDevices = voiceSettingParametersDbHelper.getStringParam(
                                voiceSettingId,
                                VoiceSettingParamType.VOICE_SETTING_TRIGGER_ENABLED_BT_DEVICES.getVoiceSettingParamTypeId());
                        StringBuilder addInfo1Builder = new StringBuilder();
                        boolean notFirst = false;
                        for(BluetoothDevice bluetoothDevice: bluetoothDeviceSet) {
                            String currentDeviceName = bluetoothDevice.getName();
                            String currentDeviceAddress = bluetoothDevice.getAddress();
                            if (btDevices.contains(currentDeviceAddress)) {
                                if (notFirst) {
                                    addInfo1Builder.append(", ");
                                }
                                addInfo1Builder.append(currentDeviceName);
                                notFirst = true;
                            }
                        }
                        addInfo1 = addInfo1Builder.toString();
                    }
                } else if (triggerType == 2) {
                    triggerTypeName = getString(R.string.voice_setting_trigger_at_time);
                    Long storedHourMinute = voiceSettingParametersDbHelper.getLongParam(
                            voiceSettingId,
                            VoiceSettingParamType.VOICE_SETTING_TIME_TO_START.getVoiceSettingParamTypeId());

                    int hour;
                    int minute;
                    if (storedHourMinute != null) {
                        int hourMinute = storedHourMinute.intValue();
                        hour = hourMinute / 100;
                        minute = hourMinute - (hour * 100);
                        final Calendar c = Calendar.getInstance();
                        c.set(Calendar.HOUR_OF_DAY, hour);
                        c.set(Calendar.MINUTE, minute);
                        addInfo1 = AppPreference.getLocalizedTime(getBaseContext(), c.getTime(), applicationLocale);

                        /*Long nextTimeDate = TimeUtils.setupAlarmForVoiceForVoiceSetting(getBaseContext(), voiceSettingId, voiceSettingParametersDbHelper);
                        if (nextTimeDate != null) {
                            c.setTimeInMillis(nextTimeDate);
                            addInfo1 += " (next " + AppPreference.getLocalizedDateTime(getBaseContext(), c.getTime(), false, applicationLocale) + ")";
                        }*/
                    }
                    Calendar calendar = Calendar.getInstance();
                    Long daysOfWeek = voiceSettingParametersDbHelper.getLongParam(
                            voiceSettingId,
                            VoiceSettingParamType.VOICE_SETTING_TRIGGER_DAY_IN_WEEK.getVoiceSettingParamTypeId());
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE", applicationLocale);
                    if (daysOfWeek != null) {
                        StringBuilder enabledDays = new StringBuilder();
                        boolean isFirst = false;
                        if (TimeUtils.isCurrentSettingIndex(daysOfWeek, 6)) {
                            calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
                            enabledDays.append(simpleDateFormat.format(calendar.getTime()));
                            isFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(daysOfWeek, 5)) {
                            if (isFirst) {
                                enabledDays.append(", ");
                            }
                            calendar.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
                            enabledDays.append(simpleDateFormat.format(calendar.getTime()));
                            isFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(daysOfWeek, 4)) {
                            if (isFirst) {
                                enabledDays.append(", ");
                            }
                            calendar.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
                            enabledDays.append(simpleDateFormat.format(calendar.getTime()));
                            isFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(daysOfWeek, 3)) {
                            if (isFirst) {
                                enabledDays.append(", ");
                            }
                            calendar.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
                            enabledDays.append(simpleDateFormat.format(calendar.getTime()));
                            isFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(daysOfWeek, 2)) {
                            if (isFirst) {
                                enabledDays.append(", ");
                            }
                            calendar.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
                            enabledDays.append(simpleDateFormat.format(calendar.getTime()));
                            isFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(daysOfWeek, 1)) {
                            if (isFirst) {
                                enabledDays.append(", ");
                            }
                            calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
                            enabledDays.append(simpleDateFormat.format(calendar.getTime()));
                            isFirst = true;
                        }
                        if (TimeUtils.isCurrentSettingIndex(daysOfWeek, 0)) {
                            if (isFirst) {
                                enabledDays.append(", ");
                            }
                            calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
                            enabledDays.append(simpleDateFormat.format(calendar.getTime()));
                        }
                        addInfo2 = enabledDays.toString();
                    }
                }
                voiceSettingTypeView.setText(triggerTypeName);
                voiceSettingAddInfo1View.setText(addInfo1);
                voiceSettingAddInfo2View.setText(addInfo2);
            }

        }

        public Long getVoiceSettingId() {
            return voiceSettingId;
        }
    }

    private class VoiceSettingsAdapter extends RecyclerView.Adapter<VoiceSettingHolder> {

        private List<Long> voiceSettingIds;

        VoiceSettingsAdapter(List<Long> voiceSettingIds) {
            this.voiceSettingIds = voiceSettingIds;
        }

        @Override
        public int getItemCount() {
            if (voiceSettingIds != null)
                return voiceSettingIds.size();

            return 0;
        }

        @Override
        public void onBindViewHolder(VoiceSettingHolder locationHolder, int position) {
            locationHolder.bindVoiceSetting(voiceSettingIds.get(position));
        }

        @Override
        public VoiceSettingHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(VoiceSettingsActivity.this);
            View v = inflater.inflate(R.layout.voice_setting_item, parent, false);
            return new VoiceSettingHolder(v);
        }
    }
}