package com.lemenzo.contacts;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/** Picker used by ACTION_INSERT_OR_EDIT to add supplied data to an existing contact. */
public final class ContactPickerActivity extends Activity {
    private static final int REQ_CONTACTS = 714;
    private ContactsRepository repo;
    private EditText search;
    private ListView list;
    private ContactAdapter adapter;
    private final Handler main = new Handler(Looper.getMainLooper());
    private final AtomicInteger generation = new AtomicInteger();
    private final ExecutorService io = Executors.newSingleThreadExecutor(r -> {
        Thread t = new Thread(r, "LemenzoContacts-Picker");
        t.setPriority(Thread.NORM_PRIORITY - 1);
        return t;
    });
    private Runnable pendingSearch;

    @Override public void onCreate(Bundle state) {
        super.onCreate(state);
        repo = new ContactsRepository(this);
        if (!ContactsPermission.hasReadWrite(this)) {
            ContactsPermission.requestReadWrite(this, REQ_CONTACTS);
            return;
        }
        build();
    }

    @Override protected void onDestroy() {
        generation.incrementAndGet();
        if (pendingSearch != null) main.removeCallbacks(pendingSearch);
        io.shutdownNow();
        super.onDestroy();
    }

    @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
        super.onRequestPermissionsResult(requestCode, permissions, results);
        if (requestCode != REQ_CONTACTS) return;
        if (ContactsPermission.hasReadWrite(this)) build();
        else { Toast.makeText(this, R.string.contacts_permission_required, Toast.LENGTH_LONG).show(); finish(); }
    }

    private void build() {
        LinearLayout root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
        root.setBackgroundColor(Ui.BG);
        root.setPadding(Ui.dp(this, 16), 0, Ui.dp(this, 16), Ui.dp(this, 18));
        Ui.applySafeInsets(this, root);

        LinearLayout title = Ui.subHeader(this, getString(R.string.choose_contact));
        root.addView(title);
        TextView desc = Ui.text(this, getString(R.string.choose_contact_desc), 13, Ui.SECONDARY);
        desc.setPadding(Ui.dp(this, 2), 0, Ui.dp(this, 2), Ui.dp(this, 12));
        root.addView(desc);

        search = Ui.input(this, getString(R.string.search_contacts));
        root.addView(search, new LinearLayout.LayoutParams(-1, Ui.dp(this, 52)));
        root.addView(Ui.space(this, 10));

        list = new ListView(this);
        list.setDivider(null);
        list.setDividerHeight(Ui.dp(this, 6));
        list.setBackgroundColor(Ui.BG);
        list.setFastScrollEnabled(true);
        list.setScrollingCacheEnabled(false);
        adapter = new ContactAdapter();
        list.setAdapter(adapter);
        list.setOnItemClickListener((parent, view, position, id) -> openEditor(adapter.getItem(position).id));
        root.addView(list, new LinearLayout.LayoutParams(-1, 0, 1));

        search.addTextChangedListener(new TextWatcher() {
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
            public void afterTextChanged(Editable s) {}
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (pendingSearch != null) main.removeCallbacks(pendingSearch);
                pendingSearch = () -> reload();
                main.postDelayed(pendingSearch, 180L);
            }
        });

        setContentView(root);
        reload();
    }

    private void reload() {
        if (search == null || adapter == null) return;
        final int g = generation.incrementAndGet();
        final String q = search.getText().toString().trim();
        io.execute(() -> {
            try {
                List<ContactSummary> data = repo.list(q, false);
                main.post(() -> { if (g == generation.get() && !isFinishing() && !isDestroyed()) adapter.replace(data); });
            } catch (SecurityException e) {
                main.post(() -> { Toast.makeText(this, R.string.contacts_permission_required, Toast.LENGTH_LONG).show(); finish(); });
            } catch (RuntimeException ignored) {
                main.post(() -> Toast.makeText(this, R.string.contact_load_failed, Toast.LENGTH_LONG).show());
            }
        });
    }

    private void openEditor(long contactId) {
        Intent target = new Intent(this, ContactEditorActivity.class).putExtra("contact_id", contactId);
        copyExtra("initial_name", target);
        copyExtra("initial_phone", target);
        copyExtra("initial_email", target);
        if (getIntent().hasExtra("initial_phone_type"))
            target.putExtra("initial_phone_type", getIntent().getIntExtra("initial_phone_type", -1));
        startActivity(target);
        finish();
    }

    private void copyExtra(String key, Intent target) {
        String value = getIntent().getStringExtra(key);
        if (value != null && !value.trim().isEmpty()) target.putExtra(key, value);
    }

    private final class ContactAdapter extends BaseAdapter {
        private final ArrayList<ContactSummary> items = new ArrayList<>();
        void replace(List<ContactSummary> data) { items.clear(); if (data != null) items.addAll(data); notifyDataSetChanged(); }
        @Override public int getCount() { return items.size(); }
        @Override public ContactSummary getItem(int position) { return items.get(position); }
        @Override public long getItemId(int position) { return items.get(position).id; }
        @Override public boolean hasStableIds() { return true; }
        @Override public View getView(int position, View convertView, ViewGroup parent) {
            LinearLayout row;
            TextView name;
            TextView phone;
            if (convertView instanceof LinearLayout && convertView.getTag() instanceof TextView[]) {
                row = (LinearLayout) convertView;
                TextView[] holder = (TextView[]) row.getTag(); name = holder[0]; phone = holder[1];
            } else {
                row = Ui.raisedCard(ContactPickerActivity.this);
                row.setOrientation(LinearLayout.VERTICAL);
                row.setGravity(Gravity.CENTER_VERTICAL);
                name = Ui.title(ContactPickerActivity.this, "", 15);
                phone = Ui.text(ContactPickerActivity.this, "", 12, Ui.SECONDARY);
                row.addView(name); row.addView(phone);
                row.setTag(new TextView[]{name, phone});
            }
            ContactSummary x = getItem(position);
            name.setText(x.name == null || x.name.trim().isEmpty() ? getString(R.string.unknown) : x.name);
            phone.setText(x.phone == null ? "" : x.phone);
            phone.setVisibility(x.phone == null || x.phone.isEmpty() ? View.GONE : View.VISIBLE);
            return row;
        }
    }
}
