package com.lemenzo.contacts;

import android.Manifest;
import android.app.*;
import android.content.*;
import android.content.pm.PackageManager;
import android.os.*;
import android.text.*;
import android.view.*;
import android.widget.*;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class MainActivity extends Activity {
    private ContactsRepository repo;
    private ContactAdapter adapter;
    private LinearLayout content;
    private EditText search;
    private int mode = 0;
    private static final int REQ = 501;
    private LinearLayout root, navHolder;

    private final ExecutorService io = Executors.newSingleThreadExecutor(r -> {
        Thread t = new Thread(r, "LemenzoContacts-IO");
        t.setPriority(Thread.NORM_PRIORITY - 1);
        return t;
    });
    private final Handler main = new Handler(Looper.getMainLooper());
    private final AtomicInteger generation = new AtomicInteger();
    private Runnable pendingSearch;

    @Override public void onCreate(Bundle b) {
        super.onCreate(b);
        repo = new ContactsRepository(this);
        mode = resolveInitialMode(getIntent());
        build();
    }

    private int resolveInitialMode(Intent intent) {
        if (intent == null) return 0;
        String action = intent.getAction();
        if ("com.android.contacts.action.LIST_STARRED".equals(action)
                || "com.android.contacts.action.LIST_FREQUENT".equals(action)
                || "com.android.contacts.action.LIST_STREQUENT".equals(action)) return 1;
        return intent.getIntExtra("mode", 0);
    }

    @Override protected void onResume() {
        super.onResume();
        if (hasPerm()) scheduleReload(0);
    }

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

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

        LinearLayout header = new LinearLayout(this);
        header.setGravity(Gravity.CENTER_VERTICAL);
        ImageView logo = new ImageView(this);
        logo.setImageResource(R.drawable.lemenzo_contacts_logo);
        logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        header.addView(logo,new LinearLayout.LayoutParams(Ui.dp(this,40),Ui.dp(this,40)));
        TextView title = Ui.title(this,getString(R.string.app_title),19);
        title.setPadding(Ui.dp(this,10),0,0,0);
        header.addView(title,new LinearLayout.LayoutParams(0,Ui.dp(this,56),1));
        ImageButton settings = Ui.iconButton(this,R.drawable.ic_settings,getString(R.string.settings));
        settings.setOnClickListener(v->startActivity(new Intent(this,SettingsActivity.class)));
        header.addView(settings,new LinearLayout.LayoutParams(Ui.dp(this,46),Ui.dp(this,46)));
        ImageButton plus = Ui.iconButton(this,R.drawable.ic_add,getString(R.string.add_contact));
        plus.setOnClickListener(v->startActivity(new Intent(this,ContactEditorActivity.class)));
        LinearLayout.LayoutParams pp = new LinearLayout.LayoutParams(Ui.dp(this,46),Ui.dp(this,46));
        pp.leftMargin = Ui.dp(this,8);
        header.addView(plus,pp);
        root.addView(header);

        TextView privacy = Ui.text(this,getString(R.string.local_only),11,Ui.BLUE);
        privacy.setPadding(Ui.dp(this,2),0,0,Ui.dp(this,10));
        root.addView(privacy);

        search = Ui.input(this,getString(R.string.search_contacts));
        root.addView(search,new LinearLayout.LayoutParams(-1,Ui.dp(this,52)));
        search.addTextChangedListener(new TextWatcher() {
            public void beforeTextChanged(CharSequence s,int a,int c,int d){}
            public void onTextChanged(CharSequence s,int a,int b,int c) {
                if (pendingSearch != null) main.removeCallbacks(pendingSearch);
                pendingSearch = () -> scheduleReload(0);
                main.postDelayed(pendingSearch,180);
            }
            public void afterTextChanged(Editable e){}
        });

        root.addView(Ui.space(this,10));
        content = new LinearLayout(this);
        content.setOrientation(LinearLayout.VERTICAL);
        root.addView(content,new LinearLayout.LayoutParams(-1,0,1));

        navHolder = new LinearLayout(this);
        navHolder.setOrientation(LinearLayout.VERTICAL);
        root.addView(navHolder,new LinearLayout.LayoutParams(-1,Ui.dp(this,64)));
        renderBottomNav();

        setContentView(root);
        if (!hasPerm()) permissionPage(); else scheduleReload(0);
    }

    private void renderBottomNav() {
        if (navHolder == null) return;
        navHolder.removeAllViews();
        LinearLayout nav = Ui.bottomNav(this,mode,
                v->{if(mode!=0){mode=0;renderBottomNav();scheduleReload(0);}},
                v->{if(mode!=1){mode=1;renderBottomNav();scheduleReload(0);}},
                v->{if(mode!=2){mode=2;renderBottomNav();scheduleReload(0);}},
                v->startActivity(new Intent(this,SettingsActivity.class)));
        navHolder.addView(nav,new LinearLayout.LayoutParams(-1,-1));
    }

    private boolean hasPerm() {
        return checkSelfPermission(Manifest.permission.READ_CONTACTS)==PackageManager.PERMISSION_GRANTED
                && checkSelfPermission(Manifest.permission.WRITE_CONTACTS)==PackageManager.PERMISSION_GRANTED;
    }

    private void permissionPage() {
        generation.incrementAndGet();
        if (adapter != null) { adapter.close(); adapter = null; }
        content.removeAllViews();
        LinearLayout card=Ui.raisedCard(this);
        card.addView(Ui.title(this,getString(R.string.permission_title),20));
        card.addView(Ui.space(this,8));
        card.addView(Ui.text(this,getString(R.string.permission_message),15,Ui.SECONDARY));
        card.addView(Ui.space(this,16));
        Button b=Ui.button(this,getString(R.string.grant_access),true);
        b.setOnClickListener(v->requestPermissions(
                new String[]{Manifest.permission.READ_CONTACTS,Manifest.permission.WRITE_CONTACTS},REQ));
        card.addView(b);
        content.addView(card);
    }

    @Override public void onRequestPermissionsResult(int r,String[] p,int[] g) {
        super.onRequestPermissionsResult(r,p,g);
        if(r==REQ&&hasPerm()) scheduleReload(0); else permissionPage();
    }

    private void scheduleReload(long delayMs) {
        if (content == null || !hasPerm() || isFinishing() || isDestroyed()) return;
        final int g = generation.incrementAndGet();
        final int requestedMode = mode;
        final String query = search == null ? "" : search.getText().toString().trim();
        Runnable job = () -> {
            if (g != generation.get()) return;
            try {
                if (requestedMode == 2) {
                    List<GroupInfo> groups = repo.groups();
                    main.post(() -> { if (g == generation.get() && !isDestroyed()) renderGroups(groups); });
                } else {
                    List<ContactSummary> all = repo.list(query, requestedMode == 1);
                    ArrayList<ContactSummary> favorites = new ArrayList<>();
                    if (requestedMode == 0 && query.isEmpty()) {
                        for (ContactSummary x : all) if (x.starred && favorites.size() < 3) favorites.add(x);
                    }
                    main.post(() -> {
                        if (g == generation.get() && !isDestroyed()) renderContacts(all, favorites, requestedMode, query);
                    });
                }
            } catch (RuntimeException ignored) {
                // Keep the existing screen responsive if ContactsProvider is temporarily busy.
            }
        };
        if (delayMs <= 0) io.execute(job); else main.postDelayed(() -> io.execute(job), delayMs);
    }

    private void renderContacts(List<ContactSummary> data, List<ContactSummary> favorites,
                                int requestedMode, String query) {
        if (adapter != null) { adapter.close(); adapter = null; }
        content.removeAllViews();

        if (requestedMode == 0 && query.isEmpty() && !favorites.isEmpty()) {
            content.addView(Ui.section(this,getString(R.string.favorites)));
            content.addView(Ui.space(this,6));
            for (ContactSummary x : favorites) content.addView(contactCard(x));
            content.addView(Ui.space(this,10));
        }

        content.addView(Ui.section(this,getString(requestedMode==1?R.string.favorites:R.string.all_contacts)));
        content.addView(Ui.space(this,6));

        if (data.isEmpty()) {
            TextView empty=Ui.text(this,getString(requestedMode==1?R.string.no_favorites:R.string.no_contacts),15,Ui.SECONDARY);
            empty.setGravity(Gravity.CENTER);
            content.addView(empty,new LinearLayout.LayoutParams(-1,0,1));
            return;
        }

        ListView list = new ListView(this);
        list.setDivider(null);
        list.setDividerHeight(Ui.dp(this,8));
        list.setBackgroundColor(Ui.BG);
        list.setPadding(0,0,0,Ui.dp(this,8));
        list.setClipToPadding(false);
        list.setFastScrollEnabled(data.size() >= 150);
        list.setScrollingCacheEnabled(false);
        adapter = new ContactAdapter(this);
        adapter.setData(data);
        list.setAdapter(adapter);
        list.setOnItemClickListener((p,v,pos,id)->
                startActivity(new Intent(this,ContactDetailActivity.class).putExtra("contact_id",id)));
        content.addView(list,new LinearLayout.LayoutParams(-1,0,1));
    }

    private View contactCard(ContactSummary x) {
        LinearLayout row=Ui.raisedCard(this);
        row.setOrientation(LinearLayout.HORIZONTAL);
        row.setGravity(Gravity.CENTER_VERTICAL);
        TextView avatar=Ui.title(this,initials(x.name),15);
        avatar.setGravity(Gravity.CENTER);
        avatar.setBackground(Ui.outline(this,Ui.SURFACE,Ui.OUTLINE,22));
        row.addView(avatar,new LinearLayout.LayoutParams(Ui.dp(this,44),Ui.dp(this,44)));
        LinearLayout tx=new LinearLayout(this);
        tx.setOrientation(LinearLayout.VERTICAL);
        tx.setPadding(Ui.dp(this,12),0,0,0);
        tx.addView(Ui.title(this,x.name==null||x.name.isEmpty()?getString(R.string.unknown):x.name,15));
        if(x.phone!=null&&!x.phone.isEmpty()) tx.addView(Ui.text(this,x.phone,12,Ui.SECONDARY));
        row.addView(tx,new LinearLayout.LayoutParams(0,-2,1));
        ImageView star=new ImageView(this);
        star.setImageResource(R.drawable.ic_star);
        row.addView(star,new LinearLayout.LayoutParams(Ui.dp(this,24),Ui.dp(this,24)));
        row.setOnClickListener(v->startActivity(
                new Intent(this,ContactDetailActivity.class).putExtra("contact_id",x.id)));
        LinearLayout holder=new LinearLayout(this);
        holder.setOrientation(LinearLayout.VERTICAL);
        holder.addView(row);
        holder.addView(Ui.space(this,6));
        return holder;
    }

    private void renderGroups(List<GroupInfo> groups) {
        if (adapter != null) { adapter.close(); adapter = null; }
        content.removeAllViews();
        LinearLayout gh=new LinearLayout(this);
        gh.setGravity(Gravity.CENTER_VERTICAL);
        TextView h=Ui.section(this,getString(R.string.groups));
        gh.addView(h,new LinearLayout.LayoutParams(0,-2,1));
        Button add=Ui.button(this,getString(R.string.new_group),false);
        add.setOnClickListener(v->showCreateGroup());
        gh.addView(add,new LinearLayout.LayoutParams(Ui.dp(this,120),Ui.dp(this,44)));
        content.addView(gh);
        content.addView(Ui.space(this,8));

        if(groups.isEmpty()){
            TextView e=Ui.text(this,getString(R.string.no_groups),15,Ui.SECONDARY);
            e.setGravity(Gravity.CENTER);
            content.addView(e,new LinearLayout.LayoutParams(-1,0,1));
            return;
        }
        ScrollView s=new ScrollView(this);
        LinearLayout box=new LinearLayout(this);
        box.setOrientation(LinearLayout.VERTICAL);
        for(GroupInfo group:groups){
            LinearLayout card=Ui.raisedCard(this);
            card.setOrientation(LinearLayout.HORIZONTAL);
            card.setGravity(Gravity.CENTER_VERTICAL);
            ImageView icon=new ImageView(this);
            icon.setImageResource(R.drawable.ic_groups);
            icon.setColorFilter(Ui.BLUE);
            card.addView(icon,new LinearLayout.LayoutParams(Ui.dp(this,28),Ui.dp(this,28)));
            LinearLayout txt=new LinearLayout(this);
            txt.setOrientation(LinearLayout.VERTICAL);
            txt.setPadding(Ui.dp(this,12),0,0,0);
            txt.addView(Ui.title(this,group.title,15));
            txt.addView(Ui.text(this,getString(R.string.group_members,group.count),12,Ui.SECONDARY));
            card.addView(txt,new LinearLayout.LayoutParams(0,-2,1));
            TextView count=Ui.title(this,String.valueOf(group.count),14);
            count.setTextColor(Ui.BLUE);
            card.addView(count);
            card.setOnClickListener(v->startActivity(new Intent(this,GroupDetailActivity.class)
                    .putExtra("group_id",group.id).putExtra("group_title",group.title)));
            box.addView(card);
            box.addView(Ui.space(this,8));
        }
        s.addView(box);
        content.addView(s,new LinearLayout.LayoutParams(-1,0,1));
    }

    private void showCreateGroup() {
        EditText e=Ui.input(this,getString(R.string.group_name));
        Ui.DialogParts dialog=Ui.showDialog(
                this,
                getString(R.string.new_group),
                getString(R.string.new_group_desc),
                e,
                getString(R.string.cancel),
                getString(R.string.save),
                false);
        dialog.positive.setOnClickListener(v->{
            String n=e.getText().toString().trim();
            if(n.isEmpty())return;
            io.execute(()->{
                repo.createGroup(n);
                main.post(()->{
                    dialog.dialog.dismiss();
                    scheduleReload(0);
                });
            });
        });
    }

    private String initials(String s) {
        if(s==null||s.trim().isEmpty())return "•";
        String[]p=s.trim().split("\\s+");
        return p[0].substring(0,1).toUpperCase()
                +(p.length>1?p[p.length-1].substring(0,1).toUpperCase():"");
    }
}
