"""
Trademark archive search.

Queries the full stored corpus of applications. The key feature is
transliteration-aware mark search: a query for "Ejaz" matches an application
whose stored variants include "E'jaz", "Ejaaz", etc. (built in Phase 1).

Filters supported:
  q            free text — matches mark (Farsi), any transliteration variant,
               translation, applicant (Farsi/EN), publication no., application no.
  nice_class   one class; matches applications listing that class
  applicant    substring on applicant name (Farsi or EN)
  date_from /  bound the publication date (Gregorian) range
  date_to
  status       'verified' | 'draft' (extraction flagged) | any

Returns applications ordered by publication date (newest first).
"""
import datetime as dt
from sqlalchemy import or_, and_
from sqlalchemy.orm import joinedload
from ..models import Application, Transliteration, Issue


def _norm_digits(s):
    if not s:
        return s
    table = {ord(c): str(i) for i, c in enumerate("۰۱۲۳۴۵۶۷۸۹")}
    table.update({ord(c): str(i) for i, c in enumerate("٠١٢٣٤٥٦٧٨٩")})
    return s.translate(table)


def search(session, q=None, nice_class=None, applicant=None,
           date_from=None, date_to=None, status=None, limit=200):
    query = (session.query(Application)
             .options(joinedload(Application.transliterations),
                      joinedload(Application.issue)))

    if q:
        q = q.strip()
        like = f"%{q}%"
        qd = f"%{_norm_digits(q)}%"
        # IDs of applications having a transliteration variant matching q
        sub = (session.query(Transliteration.application_id)
               .filter(Transliteration.value.ilike(like)))
        query = query.filter(or_(
            Application.mark_text.ilike(like),
            Application.mark_translit.ilike(like),
            Application.mark_translation.ilike(like),
            Application.applicant.ilike(like),
            Application.applicant_en.ilike(like),
            Application.pub_number.ilike(qd),
            Application.app_number.ilike(qd),
            Application.id.in_(sub),
        ))

    if applicant:
        like = f"%{applicant.strip()}%"
        query = query.filter(or_(Application.applicant.ilike(like),
                                 Application.applicant_en.ilike(like)))

    if nice_class:
        nc = _norm_digits(nice_class.strip())
        # nice_class stored like "29, 35"; match the class as a token
        query = query.filter(or_(
            Application.nice_class == nc,
            Application.nice_class.ilike(f"{nc},%"),
            Application.nice_class.ilike(f"%, {nc}"),
            Application.nice_class.ilike(f"%, {nc},%"),
            Application.nice_class.ilike(f"%,{nc}%"),
        ))

    if date_from:
        query = query.filter(Application.pub_date >= _to_date(date_from))
    if date_to:
        query = query.filter(Application.pub_date <= _to_date(date_to))

    if status == "verified":
        query = query.filter(Application.verified.is_(True))
    elif status == "draft":
        query = query.filter(Application.verified.is_(False))

    query = query.order_by(Application.pub_date.desc().nullslast(),
                           Application.id.desc())
    return query.limit(limit).all()


def _to_date(v):
    if isinstance(v, dt.date):
        return v
    try:
        return dt.date.fromisoformat(v)
    except Exception:
        return None
