package com.lemenzo.gallery.search;

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

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/** Fast local search with useful privacy-safe semantic tokens. */
public final class SearchEngine {
    public interface MotionVerifier { boolean isVerifiedMotionPhoto(MediaItem item); }
    public interface VisualVerifier { boolean isVisualDocument(MediaItem item); boolean isSelfie(MediaItem item); }
    public List<MediaItem> filter(List<MediaItem> all, String query) { return filter(all, query, null, null); }
    public List<MediaItem> filter(List<MediaItem> all, String query, MotionVerifier motionVerifier) { return filter(all, query, motionVerifier, null); }

    public List<MediaItem> filter(List<MediaItem> all, String query, MotionVerifier motionVerifier, VisualVerifier visualVerifier) {
        String needle = query == null ? "" : query.trim().toLowerCase(Locale.ROOT);
        if (needle.isEmpty()) return new ArrayList<>(all);
        String[] tokens = needle.split("\\s+");
        ArrayList<MediaItem> result = new ArrayList<>();
        DateFormat fullDate = DateFormat.getDateInstance(DateFormat.MEDIUM);
        SimpleDateFormat monthYear = new SimpleDateFormat("MMMM yyyy", Locale.getDefault());
        for (MediaItem item : all) if (matchesAll(item, tokens, fullDate, monthYear, motionVerifier, visualVerifier)) result.add(item);
        return result;
    }

    private boolean matchesAll(MediaItem item, String[] tokens, DateFormat fullDate, SimpleDateFormat monthYear, MotionVerifier motionVerifier, VisualVerifier visualVerifier) {
        String displayName = lower(item.displayName);
        String album = lower(item.bucketName);
        String mime = lower(item.mimeType);
        String type = item.type == MediaType.VIDEO ? "video videos" : "photo photos image images";
        Date date = new Date(item.sortDate());
        String dateText = (fullDate.format(date) + " " + monthYear.format(date)).toLowerCase(Locale.ROOT);
        for (String token : tokens) {
            if (token.isEmpty()) continue;
            boolean special = special(item, token, displayName, album, mime, motionVerifier, visualVerifier);
            if (!special && !displayName.contains(token) && !album.contains(token)
                    && !mime.contains(token) && !type.contains(token) && !dateText.contains(token)) return false;
        }
        return true;
    }

    private boolean special(MediaItem i, String t, String name, String album, String mime, MotionVerifier motionVerifier, VisualVerifier visualVerifier) {
        if ((t.equals("favorite") || t.equals("favorites")) && i.favorite) return true;
        if ((t.equals("screenshot") || t.equals("screenshots")) && (album.contains("screenshot") || name.contains("screenshot"))) return true;
        if ((t.equals("document") || t.equals("documents")) && ((album.contains("document") || name.contains("scan") || name.contains("document")) || (visualVerifier != null && visualVerifier.isVisualDocument(i)))) return true;
        if ((t.equals("selfie") || t.equals("selfies")) && ((album.contains("selfie") || name.contains("selfie")) || (visualVerifier != null && visualVerifier.isSelfie(i)))) return true;
        if ((t.equals("motion") || t.equals("motionphoto") || t.equals("motionphotos")) && motionVerifier != null && motionVerifier.isVerifiedMotionPhoto(i)) return true;
        if (t.equals("camera") && (album.contains("camera") || album.contains("dcim"))) return true;
        if ((t.equals("download") || t.equals("downloads")) && album.contains("download")) return true;
        if (t.equals("portrait") && i.height > i.width) return true;
        if (t.equals("landscape") && i.width > i.height) return true;
        if (t.equals("square") && Math.abs(i.width - i.height) <= Math.max(i.width, i.height) * .03f) return true;
        if (t.equals("4k") && (i.width >= 3840 || i.height >= 3840)) return true;
        if (t.equals("large") && i.size >= 20L * 1024L * 1024L) return true;
        if ((t.equals("gif") && mime.contains("gif")) || (t.equals("webp") && mime.contains("webp"))) return true;
        if ((t.equals("raw") || t.equals("dng")) && (mime.contains("dng") || name.endsWith(".dng"))) return true;
        if ((t.equals("heic") || t.equals("heif")) && (mime.contains("heic") || mime.contains("heif"))) return true;
        return false;
    }

    private static String lower(String value) { return value == null ? "" : value.toLowerCase(Locale.ROOT); }
}
