package com.example.myapplication.service;

import android.content.Context;
import android.text.TextUtils;
import com.example.myapplication.repository.CourseRepository;
import com.example.myapplication.domain.Course;
import com.example.myapplication.domain.Chapter;
import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.seg.common.Term;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

public class ClassificationService {
    public static class Result {
        public String category = "";
        public String chapter = "";
        public String bestId = "";
        public String bestTitle = "";
        public double confidence = 0.0;
        public boolean isSegmented = false;
        public java.util.List<Candidate> topCandidates = new java.util.ArrayList<>();
    }

    public static class Candidate {
        public long chapterId;
        public long subjectId;
        public String title;
        public double score;
    }

    private final Context context;
    private final CourseRepository courseRepository;
    private boolean hanLPInitialized = false;

    public ClassificationService(Context ctx) {
        this.context = ctx == null ? null : ctx.getApplicationContext();
        this.courseRepository = new CourseRepository(this.context);
        try {
            List<Term> testSegment = HanLP.segment("测试HanLP");
            hanLPInitialized = testSegment != null;
        } catch (Throwable e) {
            hanLPInitialized = false;
        }
    }

    public Result classifyWithSegmentation(String text) {
        Result out = new Result();
        if (text == null || text.trim().isEmpty()) return out;
        Set<String> noteTokens = extractKeywords(text);
        List<Course> courses = courseRepository.getAllCourses();
        double bestScore = 0.0;
        Course bestCourse = null;
        Chapter bestChapter = null;
        java.util.List<Candidate> all = new java.util.ArrayList<>();
        for (Course course : courses) {
            List<Chapter> chapters = courseRepository.getChaptersBySubjectId(course.getId());
            for (Chapter ch : chapters) {
                double score = calculateMatchScore(noteTokens, course, ch);
                if (score > 0) {
                    if (score > bestScore) {
                        bestScore = score;
                        bestCourse = course;
                        bestChapter = ch;
                    }
                    Candidate cand = new Candidate();
                    cand.chapterId = ch.getId();
                    cand.subjectId = course.getId();
                    cand.title = safe(ch.getName());
                    cand.score = score;
                    all.add(cand);
                }
            }
        }
        if (bestCourse != null && bestChapter != null) {
            out.category = safe(courseName(bestCourse));
            out.chapter = safe(bestChapter.getName());
            out.bestId = String.valueOf(bestChapter.getId());
            out.bestTitle = out.chapter;
            out.confidence = Math.max(0.0, Math.min(1.0, bestScore));
        }
        if (!all.isEmpty()) {
            java.util.Collections.sort(all, (a,b) -> Double.compare(b.score, a.score));
            int k = Math.min(3, all.size());
            for (int i = 0; i < k; i++) out.topCandidates.add(all.get(i));
        }
        return out;
    }

    private String courseName(Course c) {
        String n = c.getName();
        if (TextUtils.isEmpty(n)) n = c.getDescription();
        return n == null ? "" : n;
    }

    private String safe(String s) { return s == null ? "" : s; }

    private Set<String> extractKeywords(String text) {
        Set<String> tokens = new HashSet<>();
        if (hanLPInitialized) {
            try {
                List<Term> terms = HanLP.segment(text);
                for (Term t : terms) {
                    String w = t.word;
                    if (w != null && w.length() > 1) tokens.add(w.toLowerCase(Locale.ROOT));
                }
                return tokens;
            } catch (Throwable ignored) {}
        }
        String[] parts = text.toLowerCase(Locale.ROOT).split("[^\u4e00-\u9fa5a-zA-Z0-9]+");
        for (String p : parts) if (p.length() > 1) tokens.add(p);
        return tokens;
    }

    private double calculateMatchScore(Set<String> noteTokens, Course course, Chapter ch) {
        double total = 0.0;
        List<String> titleTokens = tokenize(ch.getName());
        List<String> keywordTokens = splitComma(ch.getKeywords());
        List<String> aliasTokens = splitComma(ch.getAliases());
        total += overlapScore(noteTokens, keywordTokens) * 0.5;
        total += overlapScore(noteTokens, titleTokens) * 0.3;
        total += overlapScore(noteTokens, aliasTokens) * 0.2;
        if (total < 0.2) {
            List<String> courseTokens = tokenize(courseName(course));
            total = Math.max(total, overlapScore(noteTokens, courseTokens) * 0.2);
        }
        return total;
    }

    private List<String> tokenize(String text) {
        List<String> out = new ArrayList<>();
        if (text == null || text.isEmpty()) return out;
        if (hanLPInitialized) {
            try {
                List<Term> terms = HanLP.segment(text);
                for (Term t : terms) {
                    String w = t.word;
                    if (w != null && w.length() > 1) out.add(w.toLowerCase(Locale.ROOT));
                }
                return out;
            } catch (Throwable ignored) {}
        }
        String[] parts = text.toLowerCase(Locale.ROOT).split("[^\u4e00-\u9fa5a-zA-Z0-9]+");
        for (String p : parts) if (p.length() > 1) out.add(p);
        return out;
    }

    private List<String> splitComma(String s) {
        List<String> out = new ArrayList<>();
        if (s == null || s.trim().isEmpty()) return out;
        String[] arr = s.split(",");
        for (String x : arr) {
            String v = x.trim();
            if (!v.isEmpty()) out.add(v.toLowerCase(Locale.ROOT));
        }
        return out;
    }

    private double overlapScore(Set<String> noteTokens, List<String> targetTokens) {
        if (noteTokens.isEmpty() || targetTokens == null || targetTokens.isEmpty()) return 0.0;
        int hit = 0;
        for (String t : targetTokens) if (noteTokens.contains(t)) hit++;
        double base = (double) hit / (double) Math.max(1, targetTokens.size());
        return Math.max(0.0, Math.min(1.0, base));
    }
}