package com.lemenzo.contacts;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
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.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public final class GroupMemberPickerActivity extends Activity {
    public static final String EXTRA_GROUP_ID = "group_id";
    public static final String EXTRA_SELECTED_IDS = "selected_contact_ids";

    private static final int REQ_CONTACTS = 821;

    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-GroupPicker");
        t.setPriority(Thread.NORM_PRIORITY - 1);
        return t;
    });

    private ContactsRepository repo;
    private long groupId;
    private EditText search;
    private ListView list;
    private PickerAdapter adapter;
    private TextView selectedCount;
    private TextView empty;
    private Button addSelected;
    private Runnable pendingSearch;

    private final ArrayList<ContactSummary> all = new ArrayList<>();
    private final ArrayList<ContactSummary> visible = new ArrayList<>();
    private final LinkedHashSet<Long> selected = new LinkedHashSet<>();

    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
        groupId = getIntent().getLongExtra(EXTRA_GROUP_ID, -1);
        repo = new ContactsRepository(this);

        if (!ContactsPermission.hasReadWrite(this)) {
            ContactsPermission.requestReadWrite(this, REQ_CONTACTS);
            return;
        }
        build();
        load();
    }

    @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();
            load();
        } 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, 16));
        Ui.applySafeInsets(this, root);

        root.addView(Ui.subHeader(this, getString(R.string.add_members)));

        TextView desc = Ui.text(this, getString(R.string.add_members_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)));

        selectedCount = Ui.text(this, getString(R.string.selected_contacts, 0), 13, Ui.BLUE);
        selectedCount.setPadding(Ui.dp(this, 2), Ui.dp(this, 10), Ui.dp(this, 2), Ui.dp(this, 8));
        root.addView(selectedCount);

        FrameLayout content = new FrameLayout(this);

        list = new ListView(this);
        list.setDivider(null);
        list.setDividerHeight(Ui.dp(this, 6));
        list.setBackgroundColor(Ui.BG);
        list.setFastScrollEnabled(true);
        list.setScrollingCacheEnabled(false);
        list.setClipToPadding(false);
        list.setPadding(0, 0, 0, Ui.dp(this, 8));

        adapter = new PickerAdapter();
        list.setAdapter(adapter);
        list.setOnItemClickListener((parent, view, position, id) -> {
            ContactSummary c = adapter.getItem(position);
            if (selected.contains(c.id)) selected.remove(c.id);
            else selected.add(c.id);
            updateSelectionUi();
            adapter.notifyDataSetChanged();
        });
        content.addView(list, new FrameLayout.LayoutParams(-1, -1));

        empty = Ui.text(this, getString(R.string.no_contacts_available), 15, Ui.SECONDARY);
        empty.setGravity(Gravity.CENTER);
        empty.setVisibility(View.GONE);
        content.addView(empty, new FrameLayout.LayoutParams(-1, -1));

        root.addView(content, new LinearLayout.LayoutParams(-1, 0, 1));

        addSelected = Ui.button(this, getString(R.string.add_selected_members), true);
        addSelected.setEnabled(false);
        addSelected.setOnClickListener(v -> finishSelection());
        root.addView(addSelected, new LinearLayout.LayoutParams(-1, Ui.dp(this, 52)));

        search.addTextChangedListener(new TextWatcher() {
            @Override public void beforeTextChanged(CharSequence s, int st, int c, int a) {}
            @Override public void onTextChanged(CharSequence s, int st, int b, int c) {
                if (pendingSearch != null) main.removeCallbacks(pendingSearch);
                final String q = s == null ? "" : s.toString();
                pendingSearch = () -> filter(q);
                main.postDelayed(pendingSearch, 120);
            }
            @Override public void afterTextChanged(Editable e) {}
        });

        setContentView(root);
    }

    private void load() {
        final int g = generation.incrementAndGet();
        io.execute(() -> {
            List<ContactSummary> contacts;
            List<ContactSummary> members;
            try {
                contacts = repo.list("", false);
                members = repo.listByGroup(groupId);
            } catch (Exception e) {
                contacts = Collections.emptyList();
                members = Collections.emptyList();
            }

            Set<Long> existing = new HashSet<>();
            for (ContactSummary member : members) existing.add(member.id);

            ArrayList<ContactSummary> available = new ArrayList<>();
            for (ContactSummary c : contacts) {
                if (!existing.contains(c.id)) available.add(c);
            }

            main.post(() -> {
                if (isDestroyed() || isFinishing() || g != generation.get()) return;
                all.clear();
                all.addAll(available);
                filter(search == null ? "" : search.getText().toString());
            });
        });
    }

    private void filter(String query) {
        String q = query == null ? "" : query.trim().toLowerCase(Locale.getDefault());
        visible.clear();
        if (q.isEmpty()) {
            visible.addAll(all);
        } else {
            for (ContactSummary c : all) {
                String name = c.name == null ? "" : c.name.toLowerCase(Locale.getDefault());
                String phone = c.phone == null ? "" : c.phone.toLowerCase(Locale.getDefault());
                if (name.contains(q) || phone.contains(q)) visible.add(c);
            }
        }
        adapter.notifyDataSetChanged();
        empty.setVisibility(visible.isEmpty() ? View.VISIBLE : View.GONE);
    }

    private void updateSelectionUi() {
        selectedCount.setText(getString(R.string.selected_contacts, selected.size()));
        addSelected.setEnabled(!selected.isEmpty());
        addSelected.setText(selected.isEmpty()
                ? getString(R.string.add_selected_members)
                : getString(R.string.add_selected_members_count, selected.size()));
    }

    private void finishSelection() {
        long[] ids = new long[selected.size()];
        int i = 0;
        for (Long id : selected) ids[i++] = id;

        Intent data = new Intent();
        data.putExtra(EXTRA_SELECTED_IDS, ids);
        setResult(RESULT_OK, data);
        finish();
    }

    private final class PickerAdapter extends BaseAdapter {
        @Override public int getCount() { return visible.size(); }
        @Override public ContactSummary getItem(int position) { return visible.get(position); }
        @Override public long getItemId(int position) { return visible.get(position).id; }

        @Override
        public View getView(int position, View old, ViewGroup parent) {
            Holder h;
            if (old == null || !(old.getTag() instanceof Holder)) {
                h = new Holder();
                old = h.row;
                old.setTag(h);
            } else {
                h = (Holder) old.getTag();
            }

            ContactSummary c = getItem(position);
            h.name.setText(c.name == null || c.name.isEmpty()
                    ? getString(R.string.unknown)
                    : c.name);
            h.phone.setText(c.phone == null ? "" : c.phone);
            h.phone.setVisibility(c.phone == null || c.phone.isEmpty() ? View.GONE : View.VISIBLE);
            h.initials.setText(initials(c.name));

            boolean checked = selected.contains(c.id);
            h.check.setText(checked ? "✓" : "");
            h.check.setTextColor(Color.WHITE);
            h.check.setBackground(Ui.outline(
                    GroupMemberPickerActivity.this,
                    checked ? Ui.BLUE : Ui.SURFACE2,
                    checked ? Ui.BLUE : Ui.OUTLINE,
                    18));

            return old;
        }

        final class Holder {
            final LinearLayout row;
            final TextView initials;
            final TextView name;
            final TextView phone;
            final TextView check;

            Holder() {
                row = Ui.card(GroupMemberPickerActivity.this);
                row.setOrientation(LinearLayout.HORIZONTAL);
                row.setGravity(Gravity.CENTER_VERTICAL);

                initials = Ui.title(GroupMemberPickerActivity.this, "•", 16);
                initials.setGravity(Gravity.CENTER);
                initials.setBackground(Ui.outline(
                        GroupMemberPickerActivity.this, Ui.SURFACE2, Ui.OUTLINE, 24));
                row.addView(initials, new LinearLayout.LayoutParams(
                        Ui.dp(GroupMemberPickerActivity.this, 48),
                        Ui.dp(GroupMemberPickerActivity.this, 48)));

                LinearLayout text = new LinearLayout(GroupMemberPickerActivity.this);
                text.setOrientation(LinearLayout.VERTICAL);
                text.setPadding(Ui.dp(GroupMemberPickerActivity.this, 14), 0,
                        Ui.dp(GroupMemberPickerActivity.this, 8), 0);

                name = Ui.title(GroupMemberPickerActivity.this, "", 16);
                phone = Ui.text(GroupMemberPickerActivity.this, "", 13, Ui.SECONDARY);
                text.addView(name);
                text.addView(phone);
                row.addView(text, new LinearLayout.LayoutParams(
                        0, ViewGroup.LayoutParams.WRAP_CONTENT, 1));

                check = Ui.title(GroupMemberPickerActivity.this, "", 14);
                check.setGravity(Gravity.CENTER);
                row.addView(check, new LinearLayout.LayoutParams(
                        Ui.dp(GroupMemberPickerActivity.this, 36),
                        Ui.dp(GroupMemberPickerActivity.this, 36)));
            }
        }
    }

    private String initials(String value) {
        if (value == null || value.trim().isEmpty()) return "•";
        String[] parts = value.trim().split("\\s+");
        String first = parts[0].substring(0, 1).toUpperCase(Locale.getDefault());
        if (parts.length == 1) return first;
        return first + parts[parts.length - 1].substring(0, 1).toUpperCase(Locale.getDefault());
    }
}
