"""
Recommendation Service
Menganalisis profil tiap cluster dan RW dari hasil clustering,
lalu menghasilkan rekomendasi tindakan berbasis kondisi yang terdeteksi.

Alur:
1. Ambil data ClusterResult + Penduduk dari DB
2. Hitung profil per cluster (rata-rata fitur, distribusi kategori)
3. Hitung profil per RW (subset dari cluster)
4. Deteksi kondisi dominan dengan threshold
5. Generate rekomendasi tindakan per kondisi
6. Buat ringkasan umum
"""

from collections import defaultdict, Counter


# ─── THRESHOLD DETEKSI ────────────────────────────────────────────────────────
# Persentase minimum anggota untuk kondisi dinyatakan "dominan"

THR_PENDIDIKAN_RENDAH  = 0.40   # >40% berpendidikan ≤ SD
THR_TIDAK_BEKERJA      = 0.35   # >35% tidak bekerja / IRT
THR_RUMAH_RENTAN       = 0.40   # >40% menumpang/sewa
THR_DISABILITAS        = 0.10   # >10% punya disabilitas (threshold lebih rendah, isu khusus)
THR_PENDIDIKAN_TINGGI  = 0.30   # >30% berpendidikan ≥ D3 (potensi produktif)
THR_PEKERJAAN_AKTIF    = 0.50   # >50% bekerja (potensi ekonomi)

# Kategori pendidikan rendah
PEND_RENDAH = {'Tidak Sekolah', 'SD', 'SMP'}
PEND_MENENGAH = {'SMA/SMK'}
PEND_TINGGI = {'D1', 'D2', 'D3', 'S1', 'S2', 'S3'}

# Kategori pekerjaan rentan
KERJA_RENTAN = {'Tidak Bekerja', 'Ibu Rumah Tangga'}
KERJA_AKTIF  = {'Bekerja', 'Pensiunan'}

# Kategori rumah rentan
RUMAH_RENTAN = {'Menumpang', 'Sewa/Kontrak'}


# ─── BANK REKOMENDASI TINDAKAN ────────────────────────────────────────────────
# Tiap kondisi punya list rekomendasi tindakan yang relevan.

REKOMENDASI_TINDAKAN = {

    'pendidikan_rendah': [
        'Penyelenggaraan program kejar paket A/B/C untuk warga usia dewasa.',
        'Pembangunan atau revitalisasi PAUD dan SD di wilayah ini.',
        'Program beasiswa pendidikan dasar bagi anak-anak keluarga rentan.',
        'Sosialisasi wajib belajar 12 tahun dan pendampingan drop-out.',
        'Pendirian taman bacaan / perpustakaan kelurahan.',
    ],

    'tidak_sekolah_dominan': [
        'Pendataan anak usia sekolah yang belum/tidak bersekolah.',
        'Koordinasi dengan Dinas Pendidikan untuk program inklusi pendidikan.',
        'Subsidi seragam dan perlengkapan sekolah bagi keluarga tidak mampu.',
        'Program PAUD berbasis RW untuk stimulasi anak usia dini.',
    ],

    'tidak_bekerja': [
        'Pelatihan vokasional/keterampilan kerja (menjahit, memasak, las, dll.).',
        'Program magang atau job fair khusus warga setempat.',
        'Fasilitasi akses ke Balai Latihan Kerja (BLK) Dinas Ketenagakerjaan.',
        'Pemberdayaan ekonomi berbasis kelompok (koperasi, PKK produktif).',
    ],

    'irt_dominan': [
        'Program pemberdayaan ibu rumah tangga melalui UMKM berbasis rumahan.',
        'Pelatihan pembuatan produk olahan untuk meningkatkan pendapatan keluarga.',
        'Fasilitasi akses permodalan mikro (KUR, BPUM) bagi pelaku usaha rumahan.',
        'Program tabungan kelompok (arisan produktif) di tingkat RW.',
    ],

    'rumah_rentan': [
        'Pendataan warga yang menumpang/sewa untuk program hunian bersubsidi.',
        'Koordinasi dengan Dinas Perumahan untuk akses Rusunawa setempat.',
        'Program bantuan uang sewa (BUS) bagi keluarga sangat miskin.',
        'Sosialisasi program KPR bersubsidi (FLPP) dari PUPR.',
    ],

    'menumpang_dominan': [
        'Prioritaskan dalam program bantuan tempat tinggal layak huni.',
        'Koordinasi dengan RT/RW untuk identifikasi keluarga yang sangat membutuhkan.',
        'Fasilitasi akses ke program bedah rumah pemerintah daerah.',
    ],

    'disabilitas': [
        'Pendataan ulang jenis dan tingkat disabilitas untuk layanan yang tepat sasaran.',
        'Fasilitas aksesibilitas publik (ramp, jalur difabel) di lingkungan RW.',
        'Koordinasi dengan Dinas Sosial untuk program PKH penyandang disabilitas.',
        'Penyediaan alat bantu (kursi roda, tongkat, alat dengar) melalui BPJS/Dinsos.',
        'Program pendampingan psikososial bagi penyandang disabilitas mental.',
        'Pelatihan keterampilan khusus yang adaptif bagi penyandang disabilitas fisik.',
    ],

    'potensi_ekonomi': [
        'Wilayah ini memiliki proporsi warga bekerja yang baik — dorong peningkatan kualitas kerja.',
        'Program peningkatan kompetensi dan sertifikasi profesi.',
        'Fasilitasi pengembangan UMKM dan akses pasar digital.',
        'Pembentukan koperasi atau BUMKel (Badan Usaha Milik Kelurahan).',
    ],

    'potensi_pendidikan': [
        'Manfaatkan warga berpendidikan tinggi sebagai relawan pengajar atau mentor.',
        'Dorong pembentukan komunitas literasi atau kelompok belajar warga.',
        'Program beasiswa lanjutan bagi anak-anak berprestasi dari keluarga kurang mampu.',
    ],

    'prioritas_tinggi_umum': [
        'Masukkan seluruh warga dalam kelompok ini ke daftar prioritas utama penerima bantuan sosial.',
        'Lakukan verifikasi lapangan untuk memastikan ketepatan sasaran program.',
        'Koordinasikan dengan aparat kelurahan untuk pemantauan berkala.',
        'Pertimbangkan intervensi terpadu (pendidikan + ekonomi + perumahan) secara bersamaan.',
    ],
}


def _hitung_profil(members: list[dict]) -> dict:
    """
    Hitung profil dari sekumpulan anggota (list dict berisi data penduduk).
    Return dict berisi persentase tiap kondisi.
    """
    n = len(members)
    if n == 0:
        return {}

    pend_counter  = Counter(m.get('pendidikan') or 'Tidak Diketahui' for m in members)
    kerja_counter = Counter(m.get('status_pekerjaan') or 'Tidak Diketahui' for m in members)
    rumah_counter = Counter(m.get('status_rumah') or 'Tidak Diketahui' for m in members)
    dis_counter   = Counter(m.get('jenis_disabilitas') or 'Tidak Ada' for m in members)

    # Hitung total per kategori
    pend_rendah_n  = sum(v for k, v in pend_counter.items() if k in PEND_RENDAH)
    tidak_sekolah_n = pend_counter.get('Tidak Sekolah', 0)
    pend_tinggi_n  = sum(v for k, v in pend_counter.items() if k in PEND_TINGGI)
    tidak_bekerja_n = sum(v for k, v in kerja_counter.items() if k in KERJA_RENTAN)
    irt_n          = kerja_counter.get('Ibu Rumah Tangga', 0)
    bekerja_n      = sum(v for k, v in kerja_counter.items() if k in KERJA_AKTIF)
    rumah_rentan_n = sum(v for k, v in rumah_counter.items() if k in RUMAH_RENTAN)
    menumpang_n    = rumah_counter.get('Menumpang', 0)
    disabilitas_n  = sum(v for k, v in dis_counter.items() if k != 'Tidak Ada')

    return {
        'total'                : n,
        'pend_rendah_pct'      : pend_rendah_n / n,
        'pend_rendah_n'        : pend_rendah_n,
        'tidak_sekolah_pct'    : tidak_sekolah_n / n,
        'tidak_sekolah_n'      : tidak_sekolah_n,
        'pend_tinggi_pct'      : pend_tinggi_n / n,
        'pend_tinggi_n'        : pend_tinggi_n,
        'tidak_bekerja_pct'    : tidak_bekerja_n / n,
        'tidak_bekerja_n'      : tidak_bekerja_n,
        'irt_pct'              : irt_n / n,
        'irt_n'                : irt_n,
        'bekerja_pct'          : bekerja_n / n,
        'bekerja_n'            : bekerja_n,
        'rumah_rentan_pct'     : rumah_rentan_n / n,
        'rumah_rentan_n'       : rumah_rentan_n,
        'menumpang_pct'        : menumpang_n / n,
        'menumpang_n'          : menumpang_n,
        'disabilitas_pct'      : disabilitas_n / n,
        'disabilitas_n'        : disabilitas_n,
        # distribusi untuk ditampilkan
        'pend_dist'            : dict(pend_counter.most_common()),
        'kerja_dist'           : dict(kerja_counter.most_common()),
        'rumah_dist'           : dict(rumah_counter.most_common()),
        'dis_dist'             : dict(dis_counter.most_common()),
    }


def _deteksi_kondisi(profil: dict) -> list[dict]:
    """
    Deteksi kondisi dominan dari profil.
    Return list kondisi: [{kode, label, nilai_pct, nilai_n, total, deskripsi}]
    """
    n       = profil.get('total', 0)
    kondisi = []

    if profil.get('pend_rendah_pct', 0) >= THR_PENDIDIKAN_RENDAH:
        pct = profil['pend_rendah_pct']
        kondisi.append({
            'kode'      : 'pendidikan_rendah',
            'label'     : 'Pendidikan Rendah Dominan',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['pend_rendah_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['pend_rendah_n']} dari {n} orang) berpendidikan ≤ SMP (melebihi threshold {int(THR_PENDIDIKAN_RENDAH*100)}%).",
            'ikon'      : 'bi-book',
            'warna'     : '#f59e0b',
        })

    if profil.get('tidak_sekolah_pct', 0) >= 0.15:  # threshold khusus untuk tidak sekolah
        pct = profil['tidak_sekolah_pct']
        kondisi.append({
            'kode'      : 'tidak_sekolah_dominan',
            'label'     : 'Tinggi: Warga Tidak/Belum Sekolah',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['tidak_sekolah_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['tidak_sekolah_n']} dari {n} orang) belum/tidak pernah sekolah (melebihi threshold 15%).",
            'ikon'      : 'bi-exclamation-triangle',
            'warna'     : '#ef4444',
        })

    if profil.get('tidak_bekerja_pct', 0) >= THR_TIDAK_BEKERJA:
        pct = profil['tidak_bekerja_pct']
        kondisi.append({
            'kode'      : 'tidak_bekerja',
            'label'     : 'Pengangguran / Tidak Bekerja Dominan',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['tidak_bekerja_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['tidak_bekerja_n']} dari {n} orang) tidak bekerja atau ibu rumah tangga (melebihi threshold {int(THR_TIDAK_BEKERJA*100)}%).",
            'ikon'      : 'bi-briefcase-x',
            'warna'     : '#f59e0b',
        })

    if profil.get('irt_pct', 0) >= 0.30:
        pct = profil['irt_pct']
        kondisi.append({
            'kode'      : 'irt_dominan',
            'label'     : 'Proporsi Ibu Rumah Tangga Tinggi',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['irt_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['irt_n']} dari {n} orang) berstatus ibu rumah tangga (melebihi threshold 30%).",
            'ikon'      : 'bi-house-heart',
            'warna'     : '#a78bfa',
        })

    if profil.get('rumah_rentan_pct', 0) >= THR_RUMAH_RENTAN:
        pct = profil['rumah_rentan_pct']
        kondisi.append({
            'kode'      : 'rumah_rentan',
            'label'     : 'Status Hunian Rentan Dominan',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['rumah_rentan_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['rumah_rentan_n']} dari {n} orang) tinggal menumpang atau sewa/kontrak (melebihi threshold {int(THR_RUMAH_RENTAN*100)}%).",
            'ikon'      : 'bi-house-exclamation',
            'warna'     : '#f59e0b',
        })

    if profil.get('menumpang_pct', 0) >= 0.20:
        pct = profil['menumpang_pct']
        kondisi.append({
            'kode'      : 'menumpang_dominan',
            'label'     : 'Proporsi Menumpang Signifikan',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['menumpang_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['menumpang_n']} dari {n} orang) tinggal menumpang (melebihi threshold 20%).",
            'ikon'      : 'bi-house-slash',
            'warna'     : '#ef4444',
        })

    if profil.get('disabilitas_pct', 0) >= THR_DISABILITAS:
        pct = profil['disabilitas_pct']
        kondisi.append({
            'kode'      : 'disabilitas',
            'label'     : 'Proporsi Penyandang Disabilitas Signifikan',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['disabilitas_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['disabilitas_n']} dari {n} orang) penyandang disabilitas (melebihi threshold {int(THR_DISABILITAS*100)}%).",
            'ikon'      : 'bi-person-wheelchair',
            'warna'     : '#06b6d4',
        })

    if profil.get('bekerja_pct', 0) >= THR_PEKERJAAN_AKTIF:
        pct = profil['bekerja_pct']
        kondisi.append({
            'kode'      : 'potensi_ekonomi',
            'label'     : 'Potensi Ekonomi: Proporsi Bekerja Tinggi',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['bekerja_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['bekerja_n']} dari {n} orang) berstatus bekerja aktif (melebihi threshold {int(THR_PEKERJAAN_AKTIF*100)}%) — potensi produktif yang dapat dikembangkan.",
            'ikon'      : 'bi-graph-up-arrow',
            'warna'     : '#10b981',
        })

    if profil.get('pend_tinggi_pct', 0) >= THR_PENDIDIKAN_TINGGI:
        pct = profil['pend_tinggi_pct']
        kondisi.append({
            'kode'      : 'potensi_pendidikan',
            'label'     : 'Potensi SDM: Proporsi Berpendidikan Tinggi',
            'nilai_pct' : round(pct * 100, 1),
            'nilai_n'   : profil['pend_tinggi_n'],
            'total'     : n,
            'deskripsi' : f"Terdeteksi {round(pct*100,1)}% anggota ({profil['pend_tinggi_n']} dari {n} orang) berpendidikan D3 ke atas (melebihi threshold {int(THR_PENDIDIKAN_TINGGI*100)}%) — potensi SDM yang dapat dioptimalkan.",
            'ikon'      : 'bi-mortarboard',
            'warna'     : '#10b981',
        })

    return kondisi


def _generate_tindakan(kondisi_list: list[dict], prioritas: str) -> list[str]:
    """
    Generate list rekomendasi tindakan dari kondisi yang terdeteksi.
    Kondisi prioritas tinggi mendapat tindakan tambahan.
    """
    tindakan = []
    kode_set = {k['kode'] for k in kondisi_list}

    for kondisi in kondisi_list:
        kode = kondisi['kode']
        if kode in REKOMENDASI_TINDAKAN:
            tindakan.extend(REKOMENDASI_TINDAKAN[kode])

    # Tambahan untuk prioritas tinggi
    if prioritas == 'Prioritas Tinggi' and kondisi_list:
        tindakan.extend(REKOMENDASI_TINDAKAN['prioritas_tinggi_umum'])

    # Deduplikasi, jaga urutan
    seen = set()
    result = []
    for t in tindakan:
        if t not in seen:
            seen.add(t)
            result.append(t)

    # Kalau tidak ada kondisi terdeteksi
    if not result:
        result = [
            'Lakukan pemantauan berkala untuk memastikan kondisi warga tetap terjaga.',
            'Pertahankan program sosial yang sudah berjalan di wilayah ini.',
        ]

    return result


def build_rekomendasi(clustering_session, cluster_results: list) -> dict:
    """
    Entry point utama.
    Terima sesi clustering + list ClusterResult (sudah di-load dengan relasi penduduk).
    Return dict berisi semua items rekomendasi + ringkasan.

    Return format:
    {
        'ringkasan': str,
        'items': [
            {
                'level': 'cluster'|'rw',
                'label': str,
                'prioritas': str,
                'kondisi': [...],
                'tindakan': [...],
            },
            ...
        ]
    }
    """
    # ── 1. Kelompokkan data per cluster ───────────────────────────────────────
    cluster_members = defaultdict(list)
    cluster_prioritas = {}

    for cr in cluster_results:
        p = cr.penduduk
        cluster_members[cr.cluster_label].append({
            'pendidikan'       : p.pendidikan,
            'status_pekerjaan' : p.status_pekerjaan,
            'status_rumah'     : p.status_rumah,
            'jenis_disabilitas': p.jenis_disabilitas,
            'rw'               : p.rw,
            'kelurahan'        : p.kelurahan,
            'kecamatan'        : p.kecamatan,
        })
        cluster_prioritas[cr.cluster_label] = cr.prioritas

    # ── 2. Analisis per cluster ───────────────────────────────────────────────
    items = []
    cluster_summaries = []

    for cl_label in sorted(cluster_members.keys()):
        members   = cluster_members[cl_label]
        prioritas = cluster_prioritas.get(cl_label, 'Prioritas Sedang')
        profil    = _hitung_profil(members)
        kondisi   = _deteksi_kondisi(profil)
        tindakan  = _generate_tindakan(kondisi, prioritas)

        items.append({
            'level'    : 'cluster',
            'label'    : f'Cluster {cl_label + 1}',
            'prioritas': prioritas,
            'kondisi'  : kondisi,
            'tindakan' : tindakan,
            'profil'   : profil,
        })

        n_kondisi = len([k for k in kondisi if 'potensi' not in k['kode']])
        cluster_summaries.append(
            f"Cluster {cl_label + 1} ({prioritas}, {len(members)} orang): "
            f"{n_kondisi} kondisi kritis terdeteksi, {len(tindakan)} rekomendasi tindakan."
        )

    # ── 3. Analisis per RW ────────────────────────────────────────────────────
    # Kelompokkan per (rw, kelurahan) — tidak bergantung cluster
    rw_members = defaultdict(list)
    rw_prioritas_counter = defaultdict(Counter)

    for cr in cluster_results:
        p   = cr.penduduk
        rw  = str(p.rw or '?').strip()
        kel = str(p.kelurahan or '').strip()
        key = f"{kel}|{rw}"
        rw_members[key].append({
            'pendidikan'       : p.pendidikan,
            'status_pekerjaan' : p.status_pekerjaan,
            'status_rumah'     : p.status_rumah,
            'jenis_disabilitas': p.jenis_disabilitas,
            'rw'               : rw,
            'kelurahan'        : kel,
            'kecamatan'        : p.kecamatan,
            'prioritas'        : cr.prioritas,
        })
        rw_prioritas_counter[key][cr.prioritas] += 1

    for key in sorted(rw_members.keys()):
        members    = rw_members[key]
        kel, rw    = key.split('|', 1)
        # Prioritas dominan di RW ini
        pc         = rw_prioritas_counter[key]
        prio_dom   = pc.most_common(1)[0][0]
        profil     = _hitung_profil(members)
        kondisi    = _deteksi_kondisi(profil)
        tindakan   = _generate_tindakan(kondisi, prio_dom)
        label      = f"RW {rw}" + (f", {kel}" if kel else "")

        items.append({
            'level'    : 'rw',
            'label'    : label,
            'prioritas': prio_dom,
            'kondisi'  : kondisi,
            'tindakan' : tindakan,
            'profil'   : profil,
        })

    # ── 4. Ringkasan umum ─────────────────────────────────────────────────────
    total_kondisi_kritis = sum(
        len([k for k in i['kondisi'] if 'potensi' not in k['kode']])
        for i in items if i['level'] == 'cluster'
    )
    total_tindakan = sum(len(i['tindakan']) for i in items if i['level'] == 'cluster')
    n_rw = len([i for i in items if i['level'] == 'rw'])

    ringkasan = (
        f"Analisis rekomendasi dihasilkan dari sesi clustering '{clustering_session.nama_sesi}' "
        f"({clustering_session.metode.upper()}, {clustering_session.n_cluster} cluster, "
        f"{clustering_session.jumlah_data} data). "
        f"Ditemukan {total_kondisi_kritis} kondisi kritis di tingkat cluster "
        f"dengan total {total_tindakan} rekomendasi tindakan. "
        f"Analisis mencakup {n_rw} RW di wilayah ini."
    )
    if cluster_summaries:
        ringkasan += " Detail per cluster: " + " | ".join(cluster_summaries)

    return {
        'ringkasan': ringkasan,
        'items'    : items,
    }