"""Small static HTML teaching parser, not a universal reader or sanitizer. No network."""
from html.parser import HTMLParser
import json
FIXTURE='<!doctype html><html lang="fa"><head><title>نمونهٔ استخراج</title></head><body><header>نام سایت</header><nav>خانه محصولات</nav><main><h1>شرایط تمرین امانت</h1><p>ابزار تا سه\u200cشنبه بازگردانده شود.</p><p>استثنا: ابزار آموزشیِ رزروشده تا دوشنبه بازگردد.</p><aside>مطالب دیگر</aside><p hidden>موعد قدیمی: جمعه</p><script>const internal_note = "متن برنامه";</script></main><footer>حقوق سایت</footer></body></html>'
class MainText(HTMLParser):
    VOID={"area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"}
    EXCLUDED={"nav","aside","header","footer","script","style","template"}
    def __init__(self):
        super().__init__(convert_charrefs=True);self.stack=[];self.parts=[];self.mains=0
    def handle_starttag(self,tag,attrs):
        attrs=dict(attrs);hidden="hidden" in attrs
        parent=self.stack[-1] if self.stack else ("",False,False)
        inside=parent[1] or tag=="main"
        excluded=parent[2] or hidden or tag in self.EXCLUDED
        if tag=="main" and not excluded:self.mains+=1
        if tag not in self.VOID:self.stack.append((tag,inside,excluded))
    def handle_startendtag(self,tag,attrs):
        self.handle_starttag(tag,attrs)
        if tag not in self.VOID:self.handle_endtag(tag)
    def handle_endtag(self,tag):
        for i in range(len(self.stack)-1,-1,-1):
            if self.stack[i][0]==tag:
                self.stack=self.stack[:i];break
    def handle_data(self,data):
        if self.stack and self.stack[-1][1] and not self.stack[-1][2] and data.strip():self.parts.append(data.strip())
    def result(self):
        if self.mains!=1:raise ValueError("Exactly one nonexcluded main expected; manual review required")
        return "\n".join(self.parts)
def extract(source):
    p=MainText();p.feed(source);p.close();return p.result()
if __name__=="__main__":
    expected="شرایط تمرین امانت\nابزار تا سه‌شنبه بازگردانده شود.\nاستثنا: ابزار آموزشیِ رزروشده تا دوشنبه بازگردد."
    actual=extract(FIXTURE);assert actual==expected
    for bad in ["<p>No main</p>","<main>A</main><main>B</main>"]:
        try:extract(bad)
        except ValueError:pass
        else:raise AssertionError("missing or duplicate main must not pass")
    assert "جمعه" not in actual and "دوشنبه" in actual
    print(json.dumps({"main_text":actual,"visible_exception_preserved":True,"hidden_old_rule_removed":True,"missing_or_duplicate_main_rejected":True},ensure_ascii=False,indent=2))
