/* OK ITHAKI V249389 - secure direct messaging for Android APK.
 * Real text/payload encryption uses Android Keystore RSA-OAEP + per-message AES-256-GCM.
 * The server receives ciphertext envelopes only. Existing legacy encrypted messages remain readable.
 */
(() => {
  'use strict';
  const VERSION='V249389-secure-dm-android-foundation';
  const IV_MARKER='v249389:rsa-oaep-aes-gcm';
  const DEFAULT_SETTINGS={
    auto_delete_seconds:86400,
    storage_mode:'encrypted_queue',
    screenshot_block:true,
    recording_block:true,
    voice_mask_mode:'light',
    voice_mask_recorded_audio_active:false,
    voice_mask_live_calls_active:false,
  };
  let cachedSettings={...DEFAULT_SETTINGS};
  let registrationPromise=null;
  const expiryTimers=new Map();
  const pendingKeyChanges=new Map();

  function bridge(){
    try{if(window.OKITHAKI_ANDROID)return window.OKITHAKI_ANDROID}catch(e){}
    try{if(window.AndroidBridge)return window.AndroidBridge}catch(e){}
    return null;
  }
  function room(){return String(localStorage.getItem('ith_room')||'ithaki-phone-test')}
  function device(){return String(localStorage.getItem('ith_device')||localStorage.getItem('device_id')||'')}
  function nickname(){return String(localStorage.getItem('ith_name')||'Μέλος')}
  function apiBase(){
    try{const b=bridge();if(b&&typeof b.getServerBase==='function'){const x=String(b.getServerBase()||'').replace(/\/+$/,'');if(x)return x}}catch(e){}
    try{return String(location.origin||'https://ok-ithaki.gr').replace(/\/+$/,'')}catch(e){return'https://ok-ithaki.gr'}
  }
  function peerFromChannel(channel){
    const parts=String(channel||'').split(':');
    if(parts.length!==3||parts[0]!=='dm')return'';
    const me=device();
    if(parts[1]===me)return parts[2];
    if(parts[2]===me)return parts[1];
    return'';
  }
  function parseJson(value,fallback={}){try{return JSON.parse(String(value||''))}catch(e){return fallback}}
  function esc(value){return String(value??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]))}
  async function jsonFetch(path,opt={}){
    const response=await fetch(apiBase()+path,Object.assign({cache:'no-store',credentials:'same-origin'},opt));
    let data={};try{data=await response.json()}catch(e){}
    if(!response.ok||data.ok===false){
      const detail=data&&data.detail;
      const message=typeof detail==='string'?detail:(detail&&detail.message)||data.message||data.reason||('HTTP '+response.status);
      const error=new Error(String(message));error.payload=data;throw error;
    }
    return data;
  }
  function nativeStatus(){
    const b=bridge();
    if(!b||typeof b.secureMessagingStatusV249389!=='function')return{ok:false,reason:'android_apk_v249389_required'};
    try{return parseJson(b.secureMessagingStatusV249389(),{ok:false,reason:'native_status_invalid'})}catch(e){return{ok:false,reason:'native_status_failed'}}
  }
  async function registerDeviceKey(force=false){
    if(registrationPromise&&!force)return registrationPromise;
    registrationPromise=(async()=>{
      const me=device();if(!me)throw new Error('Δεν βρέθηκε η ταυτότητα της συσκευής.');
      const status=nativeStatus();
      if(!status.ok||!status.public_key_b64)throw new Error('Η πραγματική End-to-end κρυπτογράφηση χρειάζεται το Android APK V249389.');
      const result=await jsonFetch('/api/secure/device/register_v249389',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({room_id:room(),device_id:me,public_key_b64:status.public_key_b64,algorithm:'RSA-OAEP-256+A256GCM'})});
      window.__ITHAKI_SECURE_READY_V249389__=true;
      return{...status,...result};
    })().catch(error=>{window.__ITHAKI_SECURE_READY_V249389__=false;throw error}).finally(()=>{setTimeout(()=>{registrationPromise=null},2000)});
    return registrationPromise;
  }
  function peerFingerprintStorageKey(peer){return'ith_secure_peer_fingerprint_v249389:'+room()+':'+String(peer||'')}
  async function peerKey(peer,acceptChanged=false){
    const result=await jsonFetch('/api/secure/device/key_v249389?room_id='+encodeURIComponent(room())+'&requester_id='+encodeURIComponent(device())+'&peer_id='+encodeURIComponent(peer));
    const fingerprint=String(result.key_fingerprint||'');
    if(!fingerprint)throw new Error('Λείπει το αποτύπωμα του δημόσιου κλειδιού του φίλου.');
    const storageKey=peerFingerprintStorageKey(peer);
    const known=String(localStorage.getItem(storageKey)||'');
    if(known&&known!==fingerprint&&!acceptChanged){
      pendingKeyChanges.set(String(peer),result);
      const error=new Error('Το κλειδί ασφαλείας του φίλου άλλαξε. Επιβεβαίωσε το νέο αποτύπωμα μαζί του πριν συνεχίσεις.');
      error.code='secure_peer_key_changed';error.oldFingerprint=known;error.newFingerprint=fingerprint;throw error;
    }
    if(!known||acceptChanged)localStorage.setItem(storageKey,fingerprint);
    pendingKeyChanges.delete(String(peer));
    return result;
  }
  async function acceptChangedPeerKey(peer){
    const pending=pendingKeyChanges.get(String(peer));
    if(pending&&pending.key_fingerprint){localStorage.setItem(peerFingerprintStorageKey(peer),String(pending.key_fingerprint));pendingKeyChanges.delete(String(peer));return pending}
    return peerKey(peer,true);
  }
  function validateEnvelopeForThisDevice(envelope,channel){
    const env=typeof envelope==='string'?parseJson(envelope,null):envelope;
    if(!env||env.v!==1||env.alg!=='RSA-OAEP-256+A256GCM')throw new Error('Μη υποστηριζόμενο ασφαλές μήνυμα.');
    const aad=parseJson(env.aad,null);if(!aad)throw new Error('Λείπουν τα ασφαλή μεταδεδομένα.');
    if(String(aad.room_id||'')!==room()||String(aad.channel||'')!==String(channel||''))throw new Error('Το ασφαλές μήνυμα δεν ανήκει σε αυτή τη συνομιλία.');
    const me=device();if(String(aad.sender_id||'')!==me&&String(aad.recipient_id||'')!==me)throw new Error('Το ασφαλές μήνυμα δεν προορίζεται για αυτή τη συσκευή.');
    return env;
  }
  async function encryptText(text,channel){
    const peer=peerFromChannel(channel);if(!peer)throw new Error('Η End-to-end κρυπτογράφηση εφαρμόζεται μόνο σε προσωπική συνομιλία φίλου.');
    await registerDeviceKey();
    const key=await peerKey(peer);
    const b=bridge();
    const aad=JSON.stringify({room_id:room(),channel:String(channel),sender_id:device(),recipient_id:peer,client_ts:Date.now()});
    const raw=b.encryptSecureMessageV249389(String(text||''),String(key.public_key_b64||''),aad);
    const maybe=parseJson(raw,null);
    if(maybe&&maybe.ok===false)throw new Error(maybe.error||'Η κρυπτογράφηση απέτυχε.');
    validateEnvelopeForThisDevice(raw,channel);
    return{iv:IV_MARKER,cipher_text:String(raw)};
  }
  async function decryptText(iv,cipher,channel,legacyDecrypt){
    if(String(iv||'')!==IV_MARKER){
      if(typeof legacyDecrypt==='function')return legacyDecrypt(iv,cipher,channel);
      return'';
    }
    const b=bridge();if(!b||typeof b.decryptSecureMessageV249389!=='function')return'🔐 Χρειάζεται το Android APK V249389 για αποκρυπτογράφηση.';
    try{
      validateEnvelopeForThisDevice(cipher,channel);
      const result=parseJson(b.decryptSecureMessageV249389(String(cipher||'')),{ok:false});
      if(!result.ok)throw new Error(result.error||'decrypt_failed');
      return String(result.plaintext||'');
    }catch(e){return'🔐 Δεν έγινε αποκρυπτογράφηση: '+String(e.message||e)}
  }
  function detectMessageType(payload){
    const parsed=parseJson(payload,null);const kind=String(parsed&&parsed.media&&parsed.media.kind||'').toLowerCase();
    if(kind==='photo'||kind==='image')return'photo';if(kind==='video')return'video';if(kind==='audio'||kind==='voice')return'audio';if(kind==='file'||kind==='document')return'file';return'message';
  }
  async function loadSettings(){
    const local=(()=>{try{const b=bridge();return b&&b.getSecureMessageSettingsV249389?parseJson(b.getSecureMessageSettingsV249389(),{}):{}}catch(e){return{}}})();
    let remote={};try{const d=device();if(d)remote=(await jsonFetch('/api/secure/settings_v249389?room_id='+encodeURIComponent(room())+'&device_id='+encodeURIComponent(d))).settings||{}}catch(e){}
    cachedSettings={...DEFAULT_SETTINGS,...remote,...local};
    return cachedSettings;
  }
  async function saveSettings(settings){
    const normalized={...DEFAULT_SETTINGS,...settings};
    const allowed=[0,1,10,30,60,300,3600,86400,259200];
    normalized.auto_delete_seconds=allowed.includes(Number(normalized.auto_delete_seconds))?Number(normalized.auto_delete_seconds):86400;
    normalized.storage_mode=normalized.storage_mode==='zero_online_only'?'zero_online_only':'encrypted_queue';
    normalized.screenshot_block=!!normalized.screenshot_block;
    normalized.recording_block=!!normalized.recording_block;
    normalized.voice_mask_mode=['none','light','deep','high','robotic'].includes(normalized.voice_mask_mode)?normalized.voice_mask_mode:'light';
    const b=bridge();if(b&&b.setSecureMessageSettingsV249389)b.setSecureMessageSettingsV249389(JSON.stringify(normalized));
    const result=await jsonFetch('/api/secure/settings_v249389',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({room_id:room(),device_id:device(),...normalized})});
    cachedSettings={...normalized,...(result.settings||{})};
    applySecureScreen();
    return cachedSettings;
  }
  async function sendMessage(channel,payload){
    const peer=peerFromChannel(channel);if(!peer)throw new Error('Δεν είναι προσωπική συνομιλία.');
    const settings=await loadSettings();
    const encrypted=await encryptText(payload,channel);
    return jsonFetch('/api/secure/messages/send_v249389',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({room_id:room(),channel:String(channel),sender_id:device(),recipient_id:peer,nickname:nickname(),envelope:encrypted.cipher_text,message_type:detectMessageType(payload),auto_delete_seconds:settings.auto_delete_seconds,storage_mode:settings.storage_mode,screenshot_block:settings.screenshot_block,recording_block:settings.recording_block,voice_mask_mode:settings.voice_mask_mode})});
  }
  function messagesPath(channel,since,limit=300){
    return'/api/secure/messages_v249389?room_id='+encodeURIComponent(room())+'&channel='+encodeURIComponent(channel)+'&viewer_id='+encodeURIComponent(device())+'&since='+encodeURIComponent(Number(since||0))+'&limit='+encodeURIComponent(limit);
  }
  async function markRead(message){
    if(!message||String(message.iv||'')!==IV_MARKER||String(message.sender_id||'')===device())return null;
    try{return await jsonFetch('/api/secure/messages/read_v249389',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({room_id:room(),channel:String(message.channel||''),message_id:String(message.message_id||''),reader_id:device()})})}catch(e){return null}
  }
  function scheduleDomExpiry(message,element,meta){
    if(!message||!element)return;
    const id=String(message.message_id||'');if(!id)return;
    let expires=Number(meta&&meta.expires_at||message.secure_meta&&message.secure_meta.expires_at||0);
    if(!expires)return;
    const remove=()=>{try{element.remove()}catch(e){}expiryTimers.delete(id)};
    const delay=Math.max(0,expires*1000-Date.now());
    if(expiryTimers.has(id))clearTimeout(expiryTimers.get(id));
    if(delay<=0){remove();return}
    expiryTimers.set(id,setTimeout(remove,Math.min(delay,2147483647)));
    const small=document.createElement('small');small.className='secureExpiryV249389';small.textContent=' · αυτόματη διαγραφή '+new Date(expires*1000).toLocaleTimeString('el-GR',{hour:'2-digit',minute:'2-digit',second:'2-digit'});const metaEl=element.querySelector('.meta');if(metaEl)metaEl.appendChild(small);
  }
  async function onMessageRendered(message,element){
    if(!message||String(message.iv||'')!==IV_MARKER)return;
    element.classList.add('secureBubbleV249389');
    const badge=document.createElement('span');badge.className='secureBadgeV249389';badge.textContent='🔐 E2EE';const metaEl=element.querySelector('.meta');if(metaEl)metaEl.prepend(badge);
    if(String(message.sender_id||'')!==device()){
      const result=await markRead(message);scheduleDomExpiry(message,element,result||message.secure_meta||{});
    }else scheduleDomExpiry(message,element,message.secure_meta||{});
  }
  function nativeSecureScreen(enabled){
    try{const b=bridge();if(b&&typeof b.setSecureScreenV249389==='function')b.setSecureScreenV249389(!!enabled)}catch(e){}
  }
  function dmChatVisible(){
    const bodyDm=document.body&&document.body.getAttribute('data-page')==='dm';const chat=document.getElementById('dmChatScreen');if(!bodyDm||!chat)return false;const style=getComputedStyle(chat);return style.display!=='none'&&style.visibility!=='hidden';
  }
  function applySecureScreen(){nativeSecureScreen(!!(cachedSettings.screenshot_block||cachedSettings.recording_block)&&dmChatVisible())}
  function installScreenObserver(){
    const observer=new MutationObserver(()=>applySecureScreen());observer.observe(document.documentElement,{subtree:true,childList:true,attributes:true,attributeFilter:['style','class','data-page']});
    document.addEventListener('visibilitychange',applySecureScreen);window.addEventListener('pagehide',()=>nativeSecureScreen(false));setInterval(applySecureScreen,2500);
  }
  const ttlOptions=[[1,'1 δευτ. — πειραματικό'],[10,'10 δευτ.'],[30,'30 δευτ.'],[60,'1 λεπτό'],[300,'5 λεπτά'],[3600,'1 ώρα'],[86400,'24 ώρες — προεπιλογή'],[259200,'72 ώρες'],[0,'Απενεργοποιημένο']];
  async function openPanel(channel){
    const menu=document.getElementById('memberMenu');if(!menu)return false;const ch=String(channel||'');const peer=peerFromChannel(ch);menu.classList.add('show');menu.innerHTML='<div class="securePanelV249389"><div class="securePanelHeadV249389"><button class="icon" data-secure-close>‹</button><b>🔐 Ασφαλής κλειδαριά μηνυμάτων</b><button class="icon" data-secure-close>×</button></div><div class="card" id="secureStatusV249389">Έλεγχος πραγματικής προστασίας…</div></div>';
    menu.querySelectorAll('[data-secure-close]').forEach(b=>b.onclick=()=>{menu.classList.remove('show');applySecureScreen()});
    let status=nativeStatus();let peerStatus=null;let keyChange=null;try{await registerDeviceKey();if(peer)peerStatus=await peerKey(peer)}catch(e){if(e&&e.code==='secure_peer_key_changed')keyChange=e;status={...status,registration_error:String(e.message||e)}}
    const settings=await loadSettings();
    const active=!!(status.ok&&status.public_key_b64&&peerStatus&&peerStatus.public_key_b64);
    const hardware=status.hardware_backed?'Προστατευμένο από ασφαλές hardware':'Android Keystore — μη εξαγώγιμο κλειδί';
    const box=document.getElementById('secureStatusV249389');if(!box)return false;
    box.innerHTML=`
      <div class="secureStateV249389 ${active?'on':'off'}"><b>Κρυπτογράφηση: End-to-end — ${active?'Ενεργή':'Αναμονή φίλου'}</b><small>${esc(active?hardware:(status.registration_error||'Ο φίλος πρέπει να ανοίξει το APK V249389 ώστε να καταχωρηθεί το δημόσιο κλειδί του.'))}</small>${peerStatus&&peerStatus.key_fingerprint?`<code>Αποτύπωμα φίλου: ${esc(String(peerStatus.key_fingerprint).match(/.{1,4}/g).slice(0,8).join(' '))}…</code>`:''}</div>
      ${keyChange?`<div class="secureKeyChangeV249389"><b>⚠️ Αλλαγή κλειδιού φίλου</b><span>Παλιό: ${esc(String(keyChange.oldFingerprint||'').slice(0,16))}…<br>Νέο: ${esc(String(keyChange.newFingerprint||'').slice(0,16))}…</span><button class="btn danger" id="secureAcceptKeyV249389">Αποδέχομαι το νέο κλειδί μετά από άμεση επιβεβαίωση με τον φίλο</button></div>`:''}
      <label>Auto-Delete<select id="secureTtlV249389">${ttlOptions.map(([v,t])=>`<option value="${v}" ${Number(settings.auto_delete_seconds)===v?'selected':''}>${esc(t)}</option>`).join('')}</select></label>
      <label>Server storage<select id="secureStorageV249389"><option value="encrypted_queue" ${settings.storage_mode==='encrypted_queue'?'selected':''}>Μόνο προσωρινό κρυπτογραφημένο πακέτο</option><option value="zero_online_only" ${settings.storage_mode==='zero_online_only'?'selected':''}>Μηδενική αποθήκευση — μόνο online</option></select></label>
      <label class="secureToggleV249389"><input id="secureShotV249389" type="checkbox" ${settings.screenshot_block?'checked':''}> Screenshot blocking: Ναι</label>
      <label class="secureToggleV249389"><input id="secureRecordV249389" type="checkbox" ${settings.recording_block?'checked':''}> Recording blocking: Ναι</label>
      <label>Voice Mask — προετοιμασία<select id="secureVoiceV249389" disabled><option value="none">Χωρίς αλλοίωση</option><option value="light">Ελαφριά — δεν είναι ακόμη ενεργή</option><option value="deep">Βαθιά — δεν είναι ακόμη ενεργή</option><option value="high">Ψηλή — δεν είναι ακόμη ενεργή</option><option value="robotic">Ρομποτική — δεν είναι ακόμη ενεργή</option></select></label>
      <div class="secureTruthV249389"><b>Επαγγελματική ένδειξη</b><span>Το Voice Mask δεν δηλώνεται ενεργό σε ζωντανές κλήσεις πριν ολοκληρωθεί και δοκιμαστεί native real-time επεξεργασία ήχου.</span></div>
      <div class="secureTruthV249389"><b>FCM</b><span>Μόνο event_id, τύπος και nonce. Μετά την αφύπνιση εμφανίζεται όνομα/avatar μόνο αφού ο server επιβεβαιώσει ότι είναι αποδεκμένος φίλος.</span></div>
      <button class="btn green" id="secureSaveV249389">Αποθήκευση ασφαλών ρυθμίσεων</button>
      <div class="date" id="secureResultV249389"></div>`;
    document.getElementById('secureVoiceV249389').value=settings.voice_mask_mode||'light';
    const acceptKey=document.getElementById('secureAcceptKeyV249389');if(acceptKey)acceptKey.onclick=async()=>{acceptKey.disabled=true;try{await acceptChangedPeerKey(peer);await openPanel(ch)}catch(e){acceptKey.disabled=false;const result=document.getElementById('secureResultV249389');if(result)result.textContent='Δεν επιβεβαιώθηκε: '+String(e.message||e)}};
    document.getElementById('secureSaveV249389').onclick=async()=>{
      const result=document.getElementById('secureResultV249389');result.textContent='Αποθήκευση…';
      try{await saveSettings({auto_delete_seconds:Number(document.getElementById('secureTtlV249389').value),storage_mode:document.getElementById('secureStorageV249389').value,screenshot_block:document.getElementById('secureShotV249389').checked,recording_block:document.getElementById('secureRecordV249389').checked,voice_mask_mode:document.getElementById('secureVoiceV249389').value});result.textContent='Οι ασφαλείς ρυθμίσεις αποθηκεύτηκαν.'}catch(e){result.textContent='Δεν αποθηκεύτηκαν: '+String(e.message||e)}
    };
    return false;
  }
  function injectCss(){if(document.getElementById('secureMessagingCssV249389'))return;const style=document.createElement('style');style.id='secureMessagingCssV249389';style.textContent=`
    .securePanelV249389{display:grid;gap:10px}.securePanelHeadV249389{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:center}.securePanelHeadV249389 b{color:#ffe3a0}.securePanelV249389 label{display:grid;gap:5px;margin:9px 0;font-weight:800}.securePanelV249389 select{min-height:44px;border-radius:13px;border:1px solid rgba(255,222,135,.28);background:#07111b;color:#fff;padding:0 10px}.secureToggleV249389{display:flex!important;align-items:center;gap:10px}.secureToggleV249389 input{width:20px;height:20px}.secureStateV249389{border-radius:15px;padding:12px;display:grid;gap:5px}.secureStateV249389.on{border:1px solid rgba(88,235,163,.5);background:rgba(20,126,80,.2)}.secureStateV249389.off{border:1px solid rgba(255,200,90,.45);background:rgba(140,91,10,.2)}.secureStateV249389 small{color:rgba(255,255,255,.72)}.secureKeyChangeV249389{display:grid;gap:8px;border-radius:13px;border:1px solid rgba(255,128,90,.5);background:rgba(140,35,20,.22);padding:10px}.secureKeyChangeV249389 span{font-size:12px;line-height:1.5}.secureStateV249389 code{display:block;margin-top:6px;font-size:10px;word-break:break-all;color:#c9f7df}.secureTruthV249389{display:grid;gap:4px;border-radius:13px;background:rgba(255,255,255,.05);padding:10px}.secureTruthV249389 span{font-size:12px;color:rgba(255,255,255,.72);line-height:1.45}.secureBubbleV249389{box-shadow:inset 0 0 0 1px rgba(105,235,180,.24)}.secureBadgeV249389{display:inline-flex;margin-right:5px;color:#86efba;font-weight:900}.secureExpiryV249389{color:#f0c86e}`;document.head.appendChild(style)}
  async function boot(){injectCss();installScreenObserver();try{await loadSettings()}catch(e){}applySecureScreen();for(let i=0;i<12;i++){if(device()){try{await registerDeviceKey();break}catch(e){}}await new Promise(r=>setTimeout(r,1500))}}
  window.ITHAKI_SECURE_V249389={VERSION,IV_MARKER,nativeStatus,registerDeviceKey,encryptText,decryptText,sendMessage,messagesPath,openPanel,onMessageRendered,loadSettings,saveSettings,applySecureScreen,peerFromChannel,acceptChangedPeerKey};
  if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot();
})();
