"""
regulations/templatetags/law_tags.py
"""

from django import template
from django.utils.html import mark_safe
import re

register = template.Library()


class LawRenderer:

    TITLE_KEYS = ('Judul', 'judul', 'Title', 'title')

    # Angka kata → angka untuk sorting
    _WORD_NUMS = {
        'PERTAMA': 1,  'SATU': 1,   'KESATU': 1,
        'KEDUA':   2,  'DUA':  2,
        'KETIGA':  3,  'TIGA': 3,
        'KEEMPAT': 4,  'EMPAT':4,
        'KELIMA':  5,  'LIMA': 5,
        'KEENAM':  6,  'ENAM': 6,
        'KETUJUH': 7,  'TUJUH':7,
        'KEDELAPAN':8, 'DELAPAN':8,
        'KESEMBILAN':9,'SEMBILAN':9,
        'KESEPULUH':10,'SEPULUH':10,
    }

    def _sort_key(self, key: str) -> tuple:
        """
        Kembalikan tuple (angka, string) agar urutan konsisten.
        'BAB 1'      → (1, 'BAB 1')
        'BAB 2'      → (2, 'BAB 2')
        'BUKU KESATU'→ (1, 'BUKU KESATU')
        'BUKU KEDUA' → (2, 'BUKU KEDUA')
        'Bagian 1'   → (1, 'Bagian 1')
        """
        upper = key.upper()
        # Coba angka arab dulu: 'BAB 10', 'Pasal 3', 'Bagian 2'
        m = re.search(r'\d+', key)
        if m:
            return (int(m.group()), key)
        # Coba angka kata: 'BUKU KESATU', 'BUKU KEDUA'
        for word, val in self._WORD_NUMS.items():
            if word in upper:
                return (val, key)
        # Fallback: sort alfabetis
        return (999, key)

    # ── Entry point ───────────────────────────────────────────────────────────

    def render(self, data: dict) -> str:
        if not isinstance(data, dict):
            return ''
        if data.get('books'):
            return self._render_books(data['books'])
        if data.get('chapters'):
            return self._render_chapters(data['chapters'])
        if data.get('articles'):
            return self._render_articles(data['articles'], '')
        return '<p class="text-center text-gray-500 my-8">Tidak ada data yang tersedia.</p>'

    # ── Level: books ──────────────────────────────────────────────────────────

    def _render_books(self, books: dict) -> str:
        parts = []
        # ✅ FIX: sort berdasarkan angka/kata agar urutan benar walau MySQL acak
        for book_key, book in sorted(books.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(book, dict):
                continue
            judul = self._get_title(book)
            parts.append(
                f'<div class="mt-12 mb-2" id="book-{book_key}">'
                f'<div class="border-t-4 border-gray-800 pt-4 pb-2 text-center">'
                f'<p class="text-lg font-bold tracking-widest uppercase">{book_key}</p>'
                f'<p class="text-base font-semibold mt-1">{judul}</p>'
                f'</div>'
            )
            if book.get('chapters'):
                parts.append(self._render_chapters(book['chapters']))
            parts.append('</div>')
        return ''.join(parts)

    # ── Level: chapters ───────────────────────────────────────────────────────

    def _render_chapters(self, chapters: dict) -> str:
        parts = []
        # ✅ FIX: sort BAB 1, BAB 2, ... BAB 10 dengan benar
        for ch_key, ch in sorted(chapters.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(ch, dict):
                continue
            judul = self._get_title(ch)
            parts.append(
                f'<div class="mt-10 mb-2" id="chapter-{ch_key}">'
                f'<div class="text-center py-2 border-b border-gray-300 mx-auto max-w-lg">'
                f'<p class="text-base font-semibold uppercase tracking-wide">{ch_key}</p>'
                f'<p class="text-sm mt-0.5">{judul}</p>'
                f'</div>'
            )
            if ch.get('articles'):
                parts.append(self._render_articles(ch['articles'], ch_key))
            if ch.get('sections'):
                parts.append(self._render_sections(ch['sections'], ch_key))
            parts.append('</div>')
        return ''.join(parts)

    # ── Level: sections ───────────────────────────────────────────────────────

    def _render_sections(self, sections: dict, ch_key: str) -> str:
        parts = []
        # ✅ FIX: sort Bagian 1, Bagian 2, ...
        for sec_key, sec in sorted(sections.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(sec, dict):
                continue
            judul = self._get_title(sec)
            parts.append(
                f'<div class="mt-6 mb-2" id="section-{ch_key}-{sec_key}">'
                f'<div class="text-center mx-auto max-w-lg">'
                f'<p class="text-sm font-medium">{sec_key}</p>'
                f'<p class="text-sm italic">{judul}</p>'
                f'</div>'
            )
            if sec.get('articles'):
                parts.append(self._render_articles(sec['articles'], ch_key, sec_key))
            if sec.get('paragraphs'):
                parts.append(self._render_paragraphs(sec['paragraphs'], ch_key, sec_key))
            parts.append('</div>')
        return ''.join(parts)

    # ── Level: paragraphs ─────────────────────────────────────────────────────

    def _render_paragraphs(self, paragraphs: dict, ch_key: str, sec_key: str) -> str:
        parts = []
        # ✅ FIX: sort Paragraf 1, Paragraf 2, ...
        for par_key, par in sorted(paragraphs.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(par, dict):
                continue
            judul = par.get('judul') or par.get('Judul', '')
            isi   = par.get('isi', '')
            parts.append(
                f'<div class="mt-4 mb-1" id="paragraph-{ch_key}-{sec_key}-{par_key}">'
                f'<div class="text-center mx-auto max-w-lg">'
                f'<p class="text-xs font-semibold uppercase tracking-widest text-gray-500">{par_key}</p>'
                f'<p class="text-xs text-gray-600">{judul}</p>'
                f'</div>'
            )
            if isi:
                parts.append(f'<p class="my-2 text-justify">{isi}</p>')
            if par.get('articles'):
                parts.append(self._render_articles(par['articles'], ch_key, sec_key, par_key))
            parts.append('</div>')
        return ''.join(parts)

    # ── Level: articles ───────────────────────────────────────────────────────

    def _render_articles(self, articles: dict, *ctx_keys) -> str:
        parts = []
        ctx = '-'.join(str(k) for k in ctx_keys)
        # ✅ FIX: sort Pasal 1, Pasal 2, ... Pasal 10 dengan benar
        for art_key, art in sorted(articles.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(art, dict):
                continue
            uid = f'article-{ctx}-{art_key}' if ctx else f'article-{art_key}'
            parts.append(
                f'<div class="mt-4 mb-1 text-center" id="{uid}">'
                f'<p class="font-semibold text-sm">{art_key}</p>'
                f'</div>'
            )
            if art.get('isi'):
                parts.append(f'<p class="text-justify my-1">{art["isi"]}</p>')
            parts.append(self._render_article_body(art, ctx, art_key))
        return ''.join(parts)

    # ── Isi pasal ─────────────────────────────────────────────────────────────

    def _render_article_body(self, art: dict, ctx: str, art_key: str) -> str:
        parts = []
        if art.get('subsections'):
            parts.append(self._render_subsections(art['subsections'], ctx, art_key))
        if art.get('numbers'):
            parts.append(self._render_numbers(art['numbers']))
        if art.get('letters'):
            parts.append(self._render_letters(art['letters']))
        return ''.join(parts)

    # ── Subsections (ayat) ────────────────────────────────────────────────────

    def _render_subsections(self, subsections: dict, ctx: str, art_key: str) -> str:
        count      = len(subsections)
        list_class = 'list-none' if count == 1 else 'list-parentheses'
        parts      = [f'<ol class="{list_class} my-1">']
        # ✅ FIX: sort pola 1, pola 2, ... agar tidak acak
        for sub_key, sub in sorted(subsections.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(sub, dict):
                continue
            uid = (f'subsection-{ctx}-{art_key}-{sub_key}'
                   if ctx else f'subsection-{art_key}-{sub_key}')
            isi = sub.get('isi', '')
            parts.append(
                f'<li class="my-1 text-justify">'
                f'<span id="{uid}">{isi}</span>'
                f'</li>'
            )
            if sub.get('numbers'):
                parts.append(self._render_numbers(sub['numbers']))
            if sub.get('letters'):
                parts.append(self._render_letters(sub['letters']))
        parts.append('</ol>')
        return ''.join(parts)

    # ── Numbers ───────────────────────────────────────────────────────────────

    def _render_numbers(self, numbers: dict) -> str:
        parts = ['<ol class="list-decimal pl-10 my-1">']
        for _, num in sorted(numbers.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(num, dict):
                continue
            isi = num.get('isi', '')
            parts.append(f'<li class="my-1 text-justify">{isi}')
            if num.get('letters'):
                parts.append(self._render_letters(num['letters']))
            if num.get('subsections'):
                parts.append(self._render_subsections(num['subsections'], '', ''))
            parts.append('</li>')
        parts.append('</ol>')
        return ''.join(parts)

    # ── Letters ───────────────────────────────────────────────────────────────

    def _render_letters(self, letters: dict) -> str:
        parts = ['<ol class="list-[lower-alpha] pl-10 my-1">']
        for _, let in sorted(letters.items(), key=lambda x: self._sort_key(x[0])):
            if not isinstance(let, dict):
                continue
            isi = let.get('isi', '')
            parts.append(f'<li class="my-1 text-justify">{isi}')
            if let.get('numbers'):
                parts.append(self._render_numbers(let['numbers']))
            if let.get('letters'):
                parts.append(self._render_letters(let['letters']))
            parts.append('</li>')
        parts.append('</ol>')
        return ''.join(parts)

    # ── Helper ────────────────────────────────────────────────────────────────

    def _get_title(self, obj: dict) -> str:
        for key in self.TITLE_KEYS:
            val = obj.get(key)
            if val:
                return val
        return ''


@register.simple_tag
def render_law_content(data: dict) -> str:
    return mark_safe(LawRenderer().render(data))