package com.lemenzo.gallery.smart;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.media.FaceDetector;
import android.util.LruCache;
import android.util.Size;

import com.lemenzo.gallery.model.MediaItem;
import com.lemenzo.gallery.model.MediaType;

/** Small-thumbnail, on-device-only visual checks. Never performs network I/O or stores biometric templates. */
public final class LocalVisualClassifier {
    private static final int DOCUMENT=1, SELFIE=2, DOCUMENT_CHECKED=4, SELFIE_CHECKED=8;
    private final ContentResolver resolver;
    private final LruCache<Long,Integer> cache=new LruCache<>(1024);

    public LocalVisualClassifier(Context context){resolver=context.getApplicationContext().getContentResolver();}

    public boolean isDocument(MediaItem item){
        if(!eligible(item))return false; Integer cached=cache.get(item.id); int flags=cached==null?0:cached;
        if((flags&DOCUMENT_CHECKED)!=0)return (flags&DOCUMENT)!=0;
        Bitmap thumb=load(item); try{if(thumb!=null&&looksDocument(thumb))flags|=DOCUMENT;}finally{if(thumb!=null&&!thumb.isRecycled())thumb.recycle();}
        flags|=DOCUMENT_CHECKED; cache.put(item.id,flags); return (flags&DOCUMENT)!=0;
    }

    public boolean isSelfie(MediaItem item){
        if(!eligible(item))return false; Integer cached=cache.get(item.id); int flags=cached==null?0:cached;
        if((flags&SELFIE_CHECKED)!=0)return (flags&SELFIE)!=0;
        Bitmap thumb=load(item); try{if(thumb!=null&&hasProminentFace(thumb))flags|=SELFIE;}finally{if(thumb!=null&&!thumb.isRecycled())thumb.recycle();}
        flags|=SELFIE_CHECKED; cache.put(item.id,flags); return (flags&SELFIE)!=0;
    }

    private boolean eligible(MediaItem item){return item!=null&&item.type==MediaType.IMAGE&&item.uri!=null;}
    private Bitmap load(MediaItem item){try{return resolver.loadThumbnail(item.uri,new Size(320,320),null);}catch(Exception ignored){return null;}}

    private static boolean looksDocument(Bitmap b){
        int w=b.getWidth(),h=b.getHeight(); if(w<16||h<16)return false; int step=Math.max(2,Math.min(w,h)/80);
        long count=0,bright=0,lowSat=0,dark=0,edges=0,edgeTests=0;
        for(int y=step;y<h;y+=step){for(int x=step;x<w;x+=step){int c=b.getPixel(x,y),r=Color.red(c),g=Color.green(c),bl=Color.blue(c);int max=Math.max(r,Math.max(g,bl)),min=Math.min(r,Math.min(g,bl));int lum=(r*54+g*183+bl*19)>>8;count++;if(lum>205)bright++;if(max-min<34)lowSat++;if(lum<58)dark++;int lc=b.getPixel(x-step,y),lu=b.getPixel(x,y-step);int l1=(Color.red(lc)*54+Color.green(lc)*183+Color.blue(lc)*19)>>8;int l2=(Color.red(lu)*54+Color.green(lu)*183+Color.blue(lu)*19)>>8;if(Math.abs(lum-l1)>28)edges++;if(Math.abs(lum-l2)>28)edges++;edgeTests+=2;}}
        return VisualHeuristics.looksLikeDocument(new VisualHeuristics.Stats(bright/(double)Math.max(1,count),lowSat/(double)Math.max(1,count),edges/(double)Math.max(1,edgeTests),dark/(double)Math.max(1,count)));
    }

    private static boolean hasProminentFace(Bitmap source){
        Bitmap rgb=null; try{
            int w=source.getWidth();if((w&1)!=0)w--;if(w<2)return false;int h=source.getHeight();
            if(h < w * 0.72f) return false; // very wide scenes are unlikely to be selfies/portraits
            rgb=Bitmap.createScaledBitmap(source,w,h,false).copy(Bitmap.Config.RGB_565,false);
            FaceDetector detector=new FaceDetector(w,h,3);FaceDetector.Face[] faces=new FaceDetector.Face[3];int found=detector.findFaces(rgb,faces);
            if(found<=0)return false;
            android.graphics.PointF midpoint=new android.graphics.PointF();
            int prominent=0;
            for(int i=0;i<found;i++){
                FaceDetector.Face f=faces[i];
                if(f==null || f.confidence()<.40f || f.eyesDistance()<w*.09f) continue;
                f.getMidPoint(midpoint);
                boolean centered=midpoint.x>=w*.18f&&midpoint.x<=w*.82f&&midpoint.y>=h*.12f&&midpoint.y<=h*.72f;
                if(centered) prominent++;
            }
            return prominent==1; // avoids classifying arbitrary group photos as selfies
        }catch(Exception ignored){return false;}finally{if(rgb!=null&&!rgb.isRecycled())rgb.recycle();}
    }
}
