#!/usr/bin/env python3
"""
Inject the ARRFLIX runtime branding shim into web-overrides/index.html.
Idempotent: if the shim is already present, exits 0 with a notice.
"""
import sys, pathlib, re

ROOT = pathlib.Path(__file__).resolve().parent.parent
TARGET = ROOT / "web-overrides" / "index.html"
MARKER_BEGIN = "/* ARRFLIX-SHIM-BEGIN */"
MARKER_END   = "/* ARRFLIX-SHIM-END */"

SHIM = MARKER_BEGIN + r"""
(function(){
  var TITLE = 'ARRFLIX';
  var BARE_RE = /^Jellyfin$/i;
  /* === English-lockdown (synchronous, runs before Jellyfin bundle) ===
     Pins UI locale to en-US so the SPA never reads navigator.language
     or the user's stored preference. Belt-and-braces against:
       - localStorage keys the SPA reads on boot
       - navigator.language / navigator.languages getters
       - fetch / XHR Accept-Language header (best-effort; most browsers
         block JS from setting it, but Jellyfin sometimes does)
       - user-config save round-trip (rewrite UICulture → en-US before send) */
  try {
    var LS_KEYS = ['appLanguage','selectedlanguage','selectedlocale','language','locale','culture'];
    for (var i=0;i<LS_KEYS.length;i++){
      try { localStorage.setItem(LS_KEYS[i], 'en-US'); } catch(e){}
    }
  } catch(e){}
  try {
    var EN = ['en-US','en'];
    Object.defineProperty(Navigator.prototype, 'language',  { get:function(){return 'en-US';}, configurable:true });
    Object.defineProperty(Navigator.prototype, 'languages', { get:function(){return EN.slice();}, configurable:true });
  } catch(e){
    /* fallback for engines that won't let us redefine on the prototype */
    try { Object.defineProperty(navigator, 'language',  { get:function(){return 'en-US';}, configurable:true }); } catch(e2){}
    try { Object.defineProperty(navigator, 'languages', { get:function(){return ['en-US','en'];}, configurable:true }); } catch(e2){}
  }
  /* fetch wrapper: strip Accept-Language on outbound requests, and rewrite
     any user-config save body so UICulture is pinned to en-US. */
  try {
    if (window.fetch) {
      var _origFetch = window.fetch;
      window.fetch = function(input, init){
        try {
          init = init || {};
          /* strip Accept-Language if present on a plain object headers init */
          if (init.headers) {
            if (init.headers instanceof Headers) {
              try { init.headers.delete('Accept-Language'); } catch(e){}
            } else if (typeof init.headers === 'object') {
              for (var k in init.headers){ if (k && k.toLowerCase() === 'accept-language') { try { delete init.headers[k]; } catch(e){} } }
            }
          }
          /* rewrite user-config save: POST /Users/{id}/Configuration */
          var url = (typeof input === 'string') ? input : (input && input.url) || '';
          var method = (init.method || (input && input.method) || 'GET').toUpperCase();
          if (url && /\/Users\/[^/]+\/Configuration(\?|$)/.test(url) && method === 'POST' && init.body) {
            try {
              var body = init.body;
              if (typeof body === 'string') {
                var obj = JSON.parse(body);
                if (obj && typeof obj === 'object') {
                  obj.UICulture = 'en-US';
                  init.body = JSON.stringify(obj);
                }
              }
            } catch(e){}
          }
        } catch(e){}
        return _origFetch.call(this, input, init);
      };
    }
  } catch(e){}
  /* XHR wrapper: strip Accept-Language; rewrite user-config save body. */
  try {
    if (window.XMLHttpRequest) {
      var _open = XMLHttpRequest.prototype.open;
      var _setHeader = XMLHttpRequest.prototype.setRequestHeader;
      var _send = XMLHttpRequest.prototype.send;
      XMLHttpRequest.prototype.open = function(method, url){
        this.__arrflix_method = (method || 'GET').toUpperCase();
        this.__arrflix_url = url || '';
        return _open.apply(this, arguments);
      };
      XMLHttpRequest.prototype.setRequestHeader = function(name, value){
        if (name && String(name).toLowerCase() === 'accept-language') return;
        return _setHeader.apply(this, arguments);
      };
      XMLHttpRequest.prototype.send = function(body){
        try {
          if (this.__arrflix_url && /\/Users\/[^/]+\/Configuration(\?|$)/.test(this.__arrflix_url) && this.__arrflix_method === 'POST' && typeof body === 'string') {
            try {
              var obj = JSON.parse(body);
              if (obj && typeof obj === 'object') {
                obj.UICulture = 'en-US';
                body = JSON.stringify(obj);
              }
            } catch(e){}
          }
        } catch(e){}
        return _send.call(this, body);
      };
    }
  } catch(e){}
  /* Re-pin localStorage on every visibility change (SPA may rewrite on user save) */
  function pinLocale(){
    try {
      var L = ['appLanguage','selectedlanguage','selectedlocale','language','locale','culture'];
      for (var i=0;i<L.length;i++){ try { if (localStorage.getItem(L[i]) !== 'en-US') localStorage.setItem(L[i], 'en-US'); } catch(e){} }
    } catch(e){}
  }
  /* === end english-lockdown synchronous block === */
  function getFavicon(){
    var l = document.querySelector('link[rel="shortcut icon"], link[rel="icon"]');
    return l && l.href ? l.href : null;
  }
  function lockTitle(){
    try {
      var t = document.title || '';
      if (BARE_RE.test(t)) { document.title = TITLE; return; }
      if (/Jellyfin/i.test(t)) {
        var cleaned = t.replace(/\s*[-|]\s*Jellyfin\s*$/i, '').replace(/Jellyfin/gi, TITLE);
        if (!cleaned) { document.title = TITLE; }
        else if (!/ARRFLIX/i.test(cleaned)) { document.title = cleaned + ' - ' + TITLE; }
        else { document.title = cleaned; }
      }
    } catch(e){}
  }
  function lockFavicon(){
    try {
      var fav = getFavicon();
      if (!fav || fav.indexOf('data:image') !== 0) return;
      var icons = document.querySelectorAll('link[rel*="icon"]');
      for (var i=0;i<icons.length;i++){ if (icons[i].href !== fav) icons[i].href = fav; }
    } catch(e){}
  }
  function nukeSettings(){
    try {
      var nodes = document.querySelectorAll('a[href*="mypreferencesmenu"], [to*="mypreferencesmenu"]');
      for (var i=0;i<nodes.length;i++){
        var el = nodes[i];
        var p = el.closest && (el.closest('li, .MuiListItem-root, [role="menuitem"]')) || el;
        if (p && p.style && p.style.display !== 'none') p.style.display = 'none';
      }
    } catch(e){}
  }
  function start(){
    lockTitle(); lockFavicon(); nukeSettings(); pinLocale();
    try {
      var head = document.head || document.querySelector('head');
      if (head && window.MutationObserver) {
        new MutationObserver(function(){ lockTitle(); lockFavicon(); }).observe(head, { childList:true, subtree:true, characterData:true, attributes:true, attributeFilter:['href'] });
      }
    } catch(e){}
    try {
      if (document.body && window.MutationObserver) {
        new MutationObserver(function(){ nukeSettings(); }).observe(document.body, { childList:true, subtree:true });
      }
    } catch(e){}
    setInterval(function(){
      var t = document.title || '';
      if (BARE_RE.test(t) || /Jellyfin/i.test(t)) lockTitle();
      var fav = getFavicon();
      if (fav && fav.indexOf('data:image') !== 0) lockFavicon();
      nukeSettings();
      pinLocale();
    }, 1000);
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', start, { once:true });
  } else { start(); }
  if ('serviceWorker' in navigator) {
    try {
      navigator.serviceWorker.getRegistrations().then(function(regs){
        regs.forEach(function(r){
          try {
            var url = (r.active && r.active.scriptURL) || '';
            if (url.indexOf('serviceworker.js') !== -1) { r.unregister(); }
          } catch(e){}
        });
      }).catch(function(){});
      if (window.caches && caches.keys) {
        caches.keys().then(function(keys){ keys.forEach(function(k){ caches.delete(k); }); }).catch(function(){});
      }
    } catch(e){}
  }
})();
""" + MARKER_END

WRAPPED = "<script>" + SHIM + "</script>"

def main():
    html = TARGET.read_text(encoding="utf-8")
    if MARKER_BEGIN in html:
        # Replace the existing shim block in place
        pattern = re.compile(r"<script>" + re.escape(MARKER_BEGIN) + r".*?" + re.escape(MARKER_END) + r"</script>", re.DOTALL)
        # Use a callable replacement to bypass backreference parsing in WRAPPED
        new_html, n = pattern.subn(lambda _m: WRAPPED, html, count=1)
        if n != 1:
            print("ERROR: shim markers present but could not match for replacement", file=sys.stderr)
            sys.exit(2)
        TARGET.write_text(new_html, encoding="utf-8")
        print(f"Replaced existing shim ({len(WRAPPED)} chars).")
        return
    # Insert immediately after <head>
    needle = "<head>"
    idx = html.find(needle)
    if idx < 0:
        print("ERROR: <head> not found in target", file=sys.stderr)
        sys.exit(1)
    insert_at = idx + len(needle)
    new_html = html[:insert_at] + WRAPPED + html[insert_at:]
    TARGET.write_text(new_html, encoding="utf-8")
    print(f"Inserted shim ({len(WRAPPED)} chars) after <head> at offset {insert_at}.")

if __name__ == "__main__":
    main()
