/* OK ITHAKI V249518 - UNIVERSAL ACTUAL FILE SHARE / COMMUNITY VIDEO / SHARED AES KEYS */
(function(){
'use strict';
if(window.__ITHAKI_V249518_COMMUNITY_VIDEO_KEYS__)return;
window.__ITHAKI_V249518_COMMUNITY_VIDEO_KEYS__={version:'V249518',actualFileShare:true,communityVideoContain:true,sideRail:true,fullscreen:true,pollsForMembers:true,sharedAes256Gcm:true,keyFile:true,keyFingerprintQr:true,avatarEscape:true,at:Date.now()};
const I=()=>window.ITH||{};const S=()=>window.state||I().state||{};const $=id=>document.getElementById(id);
const esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
const enc=new TextEncoder(),dec=new TextDecoder();let replyTo=null,lastMessages=[],loading=false,lastShareMidV249526R6='',lastShareAtV249526R6=0;
function room(){return String(S().room||localStorage.getItem('ith_room')||'ithaki-phone-test')}
function device(){return String(S().device||localStorage.getItem('ith_device')||'')}
function nickname(){return String(S().name||localStorage.getItem('ith_name')||localStorage.getItem('ith_nickname')||'Μέλος')}
function sid(){return String(S().currentSpace||String(S().currentSpaceChannel||'').replace(/^space:/,''))}
function channel(){return String(S().currentSpaceChannel||('space:'+sid()))}
function active(){return document.body?.getAttribute('data-page')==='spaces'&&!!sid()&&!!$('spaceMsgs')}
function base(){return location.origin.replace(/\/$/,'')}
function headers(json=false){const h={};if(json)h['Content-Type']='application/json';try{const t=localStorage.getItem('ith_public_token')||localStorage.getItem('ith_token')||'';if(t)h['X-ITHAKI-TOKEN']=t}catch(e){}return h}
async function api(path,opt={}){const r=await fetch(base()+path,Object.assign({cache:'no-store'},opt,{headers:Object.assign(headers(!!opt.body),opt.headers||{})}));const txt=await r.text();let d={};try{d=txt?JSON.parse(txt):{}}catch(e){d={detail:txt}}if(!r.ok)throw Error(typeof d.detail==='string'?d.detail:(d.detail?.message||d.message||('HTTP '+r.status)));return d}
function toast(m,ms=6000){try{if(I().toast)return I().toast(m,ms)}catch(e){}const t=$('toast');if(t){t.textContent=m;t.classList.add('show');setTimeout(()=>t.classList.remove('show'),ms)}else alert(m)}
function addCss(){if($('ith518Css'))return;const st=document.createElement('style');st.id='ith518Css';st.textContent=`
#spaceMsgs.ith518Messages{padding:8px 8px 18px!important}.ith518Msg{position:relative;display:grid;grid-template-columns:38px minmax(0,1fr);gap:8px;margin:8px 0;align-items:start}.ith518Msg.mine{grid-template-columns:minmax(0,1fr) 38px}.ith518Msg.mine .ith518Avatar{grid-column:2}.ith518Msg.mine .ith518Bubble{grid-row:1;grid-column:1;background:rgba(54,240,160,.095);border-color:rgba(54,240,160,.22)}.ith518Avatar{width:38px;height:38px;border-radius:50%;overflow:hidden;display:grid;place-items:center;background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.14);color:#fff;font-weight:900;cursor:pointer;touch-action:manipulation}.ith518Avatar img{width:100%;height:100%;object-fit:cover}.ith518Bubble{min-width:0;border-radius:18px;padding:9px;background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.10);box-shadow:0 8px 24px rgba(0,0,0,.16)}.ith518MsgTop{display:flex;align-items:center;gap:7px;margin-bottom:5px}.ith518MsgTop b{color:#ffe39b}.ith518MsgTop time{margin-left:auto;font-size:10px;color:rgba(238,247,255,.54)}.ith518ReplyQuote{border-left:3px solid rgba(255,217,110,.65);padding:6px 8px;margin-bottom:7px;border-radius:7px;background:rgba(255,217,110,.065);font-size:12px}.ith518Text{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.42}.ith518SecureMark{display:inline-flex;gap:5px;align-items:center;font-size:10px;border:1px solid rgba(54,240,160,.32);border-radius:999px;padding:3px 7px;color:#8dffc5;background:rgba(54,240,160,.06)}
.ith518MediaWrap{position:relative;margin-top:7px;border-radius:18px;overflow:hidden;background:#05080d;border:1px solid rgba(255,255,255,.12);min-height:110px}.ith518MediaStage{position:relative;width:100%;display:grid;place-items:center;background:#03060a}.ith518MediaStage video,.ith518MediaStage img{display:block;width:100%;max-width:100%;height:auto;max-height:min(72vh,680px);object-fit:contain!important;object-position:center;background:#000}.ith518MediaStage audio{width:calc(100% - 18px);margin:18px 9px}.ith518Rail{position:absolute;right:7px;top:50%;transform:translateY(-50%);z-index:5;display:flex;flex-direction:column;gap:7px;padding:7px 5px;border-radius:18px;background:rgba(5,10,17,.48);border:1px solid rgba(255,255,255,.15);backdrop-filter:blur(10px)}.ith518Rail button{width:62px;min-height:48px;border-radius:15px;border:1px solid rgba(255,255,255,.16);background:rgba(0,0,0,.52);color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;padding:4px 3px;touch-action:manipulation}.ith518Rail button .ith518RailIcon{font-size:17px;line-height:1}.ith518Rail button .ith518RailLabel{font-size:9px;line-height:1.05;font-weight:800;white-space:nowrap}.ith518FileCard{display:flex;align-items:center;gap:10px;padding:14px 58px 14px 13px;min-height:70px}.ith518FileCard .ico{font-size:32px}.ith518FileCard .meta{min-width:0}.ith518FileCard b{display:block;overflow:hidden;text-overflow:ellipsis}.ith518FileCard small{display:block;color:rgba(238,247,255,.60)}
.ith518TextActions{display:flex;gap:6px;flex-wrap:wrap;margin-top:7px}.ith518TextActions button{border:1px solid rgba(255,255,255,.11);background:rgba(255,255,255,.055);color:#fff;border-radius:999px;padding:6px 9px;font-size:12px}.ith518Full{position:fixed;inset:0;z-index:100000;background:rgba(0,0,0,.96);display:flex;flex-direction:column}.ith518FullHead{height:54px;display:flex;align-items:center;gap:9px;padding:0 10px;background:rgba(6,13,22,.82);border-bottom:1px solid rgba(255,255,255,.12)}.ith518FullHead b{flex:1;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ith518FullHead button{width:40px;height:40px;border-radius:50%;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.14);color:#fff;font-size:22px}.ith518FullBody{flex:1;min-height:0;display:grid;place-items:center;overflow:auto}.ith518FullBody video,.ith518FullBody img{width:100%;height:100%;max-width:100%;max-height:100%;object-fit:contain!important;background:#000}.ith518FullBody audio{width:min(92vw,720px)}
.ith518Panel{position:fixed;inset:0;z-index:100001;background:rgba(3,9,16,.88);backdrop-filter:blur(10px);display:flex;flex-direction:column}.ith518PanelHead{display:flex;align-items:center;gap:8px;padding:10px;border-bottom:1px solid rgba(255,255,255,.12)}.ith518PanelHead b{flex:1;color:#ffe39b}.ith518PanelHead button{width:42px;height:42px;border-radius:50%;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.13);color:#fff;font-size:21px}.ith518PanelBody{flex:1;min-height:0;overflow:auto;padding:12px}.ith518Grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.ith518Choice{min-height:58px;text-align:left;border-radius:17px;padding:11px;background:rgba(255,255,255,.065);border:1px solid rgba(255,255,255,.12);color:#fff;font-weight:900}.ith518Choice.gold{border-color:rgba(255,217,110,.56);background:rgba(255,217,110,.10)}.ith518Choice.green{border-color:rgba(54,240,160,.48);background:rgba(54,240,160,.09)}.ith518Card{padding:12px;border-radius:17px;background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.11);margin-bottom:10px}.ith518Card input,.ith518Card textarea{width:100%;box-sizing:border-box;margin-top:7px}.ith518Qr{display:block;width:min(78vw,360px);height:auto;margin:14px auto;border-radius:18px;background:#fff;padding:8px}.ith518KeyFp{font-family:monospace;word-break:break-all;padding:10px;border-radius:12px;background:rgba(0,0,0,.35);color:#a8ffd1}.ith518PollOption{display:flex;width:100%;justify-content:space-between;gap:10px;margin-top:7px;border-radius:14px;padding:10px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.11);color:#fff}.ith518PollOption.mine{border-color:rgba(54,240,160,.52)}
#ith517ReplyBox.ith518ReplyActive{display:flex!important;align-items:center;gap:8px;background:rgba(255,217,110,.08);border-color:rgba(255,217,110,.32)}#ith517ReplyBox .text{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#ith517ReplyBox button{border:0;background:transparent;color:#fff;font-size:20px}
@media(max-width:680px){.ith518Msg{grid-template-columns:32px minmax(0,1fr);gap:6px}.ith518Msg.mine{grid-template-columns:minmax(0,1fr) 32px}.ith518Avatar{width:32px;height:32px}.ith518Bubble{padding:7px}.ith518MediaStage video,.ith518MediaStage img{max-height:62vh}.ith518Rail{right:5px;gap:5px;padding:5px 4px}.ith518Rail button{width:35px;height:35px}.ith518Grid{grid-template-columns:1fr}.ith518FullHead{height:50px}}
`;document.head.appendChild(st)}
function b64(bytes){let s='';for(let i=0;i<bytes.length;i+=0x8000)s+=String.fromCharCode(...bytes.subarray(i,i+0x8000));return btoa(s)}
function unb64(s){const x=atob(String(s||''));const a=new Uint8Array(x.length);for(let i=0;i<x.length;i++)a[i]=x.charCodeAt(i);return a}
async function digest(bytes){const d=new Uint8Array(await crypto.subtle.digest('SHA-256',bytes));return [...d].map(x=>x.toString(16).padStart(2,'0')).join('')}
function keyStore(){return 'ith_community_aes_key_v249518_'+room()+'_'+sid()}
function lockStore(){return 'ith_community_aes_enabled_v249518_'+room()+'_'+sid()}
function getKeyB64(){try{return localStorage.getItem(keyStore())||''}catch(e){return''}}
function lockEnabled(){try{return localStorage.getItem(lockStore())==='1'&&!!getKeyB64()}catch(e){return false}}
async function keyInfo(){const raw=unb64(getKeyB64());return{raw,fingerprint:raw.length?await digest(raw):''}}
async function aesKey(){const raw=unb64(getKeyB64());if(raw.length!==32)throw Error('Δεν υπάρχει έγκυρο κλειδί κοινότητας.');return crypto.subtle.importKey('raw',raw,{name:'AES-GCM'},false,['encrypt','decrypt'])}
async function cryptBytes(bytes){const iv=crypto.getRandomValues(new Uint8Array(12)),key=await aesKey();const out=new Uint8Array(await crypto.subtle.encrypt({name:'AES-GCM',iv},key,bytes));return{iv:b64(iv),ct:b64(out)}}
async function decryptBytes(iv,ct){const key=await aesKey();return new Uint8Array(await crypto.subtle.decrypt({name:'AES-GCM',iv:unb64(iv)},key,unb64(ct)))}
const PREFIX='ITHAKI-COMMUNITY-AES-V249518:';
async function encryptText(text){const z=await cryptBytes(enc.encode(text));const k=await keyInfo();return PREFIX+btoa(unescape(encodeURIComponent(JSON.stringify({v:249518,alg:'A256GCM',kid:k.fingerprint.slice(0,16),iv:z.iv,ct:z.ct,type:'text'}))))}
async function decryptText(text){if(!String(text||'').startsWith(PREFIX))return null;const o=JSON.parse(decodeURIComponent(escape(atob(String(text).slice(PREFIX.length)))));const out=await decryptBytes(o.iv,o.ct);return{text:dec.decode(out),secure:true,kid:o.kid||''}}
function parseMessage(raw){let body=String(raw||''),media=null,reply=null;try{const o=JSON.parse(body);if(o&&typeof o==='object'){body=String(o.body??o.text??'');media=o.media||null;reply=o.reply_to||null}}catch(e){}return{body,media,reply}}
function fullUrl(u){u=String(u||'');if(!u)return'';if(/^blob:|^data:|^https?:/i.test(u))return u;return base()+'/'+u.replace(/^\/+/, '')}
function mediaKind(m){const k=String(m?.original_kind||m?.kind||'').toLowerCase(),t=String(m?.original_type||m?.mime_type||m?.type||'').toLowerCase(),n=String(m?.original_name||m?.filename||m?.name||'').toLowerCase();if(k==='video'||t.startsWith('video/')||/\.(mp4|webm|mov|m4v|3gp)$/.test(n))return'video';if(k==='photo'||k==='image'||t.startsWith('image/')||/\.(png|jpe?g|gif|webp)$/.test(n))return'photo';if(k==='audio'||t.startsWith('audio/')||/\.(mp3|wav|m4a|ogg|webm)$/.test(n))return'audio';return'file'}
function mediaName(m){return String(m?.original_name||m?.filename||m?.name||'OK_ITHAKI_file')}
function mediaMime(m){return String(m?.original_type||m?.mime_type||m?.type||'application/octet-stream')}
function mediaUrl(m){return fullUrl(m&&(m.url||m.file_url||m.media_url)||'')}
async function fetchBlob(url){const r=await fetch(fullUrl(url),{cache:'no-store',headers:headers(false)});if(!r.ok)throw Error('Δεν φορτώθηκε το αρχείο ('+r.status+').');return r.blob()}
async function shareBlob(blob,name,mime){if(window.__ITHAKI_V249523_SHARE_READY__&&I().shareBlobV249523)return I().shareBlobV249523(blob,name,mime);mime=mime||blob.type||'application/octet-stream';name=name||'OK_ITHAKI_file';const br=window.AndroidBridge||window.OKITHAKI_ANDROID;try{if(br&&typeof br.shareBase64File==='function'){const data=await new Promise((res,rej)=>{const fr=new FileReader();fr.onload=()=>res(String(fr.result||''));fr.onerror=()=>rej(fr.error);fr.readAsDataURL(blob)});const rr=String(br.shareBase64File(name,mime,data)||'');if(/^ok/i.test(rr))return true}}catch(e){console.warn(e)}try{const f=new File([blob],name,{type:mime});if(navigator.canShare&&navigator.canShare({files:[f]})&&navigator.share){await navigator.share({files:[f],title:'OK ITHAKI'});return true}}catch(e){if(e?.name==='AbortError')return false;console.warn(e)}const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=name;document.body.appendChild(a);a.click();setTimeout(()=>{URL.revokeObjectURL(a.href);a.remove()},1500);return true}
async function actualBlob(m){if(!m)throw Error('Δεν υπάρχει αρχείο.');if(m.encrypted_v249518){const encrypted=await fetchBlob(mediaUrl(m));const packed=new Uint8Array(await encrypted.arrayBuffer());let o;try{o=JSON.parse(dec.decode(packed))}catch(e){throw Error('Μη έγκυρο κρυπτογραφημένο αρχείο.')}const plain=await decryptBytes(o.iv,o.ct);return new Blob([plain],{type:o.original_type||m.original_type||'application/octet-stream'})}return fetchBlob(mediaUrl(m))}
async function shareMedia(m){const u=mediaUrl(m);if(window.__ITHAKI_V249523_SHARE_READY__&&I().shareActualFileV249523&&u&&!m?.encrypted_v249518)return I().shareActualFileV249523(u,mediaName(m),mediaMime(m));const br=window.AndroidBridge||window.OKITHAKI_ANDROID;if(!m?.encrypted_v249518&&u&&br&&typeof br.shareRemoteFileV249521==='function'&&/^https?:/i.test(u)){const r=String(br.shareRemoteFileV249521(u,mediaName(m),mediaMime(m))||'');if(/^(ok|queued)/i.test(r))return true;throw Error(r||'native share failed')}const blob=await actualBlob(m);return shareBlob(blob,mediaName(m),mediaMime(m))}
async function downloadMedia(m){const blob=await actualBlob(m),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=mediaName(m);document.body.appendChild(a);a.click();setTimeout(()=>{URL.revokeObjectURL(a.href);a.remove()},1500)}
async function shareTextFile(text,name='ITHAKI_message.txt'){return shareBlob(new Blob([String(text||'')],{type:'text/plain;charset=utf-8'}),name,'text/plain')}
function initials(n){return String(n||'Μ').trim().split(/\s+/).slice(0,2).map(x=>x[0]||'').join('').toUpperCase()||'Μ'}
function dateText(v){const n=Number(v||0);try{return new Date(n<1e12?n*1000:n).toLocaleString('el-GR',{day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'})}catch(e){return''}}
async function materializeEncryptedMedia(m,host){if(!m?.encrypted_v249518)return m;if(!getKeyB64()){host.innerHTML='<div class="ith518FileCard"><span class="ico">🔒</span><div class="meta"><b>Κρυπτογραφημένο αρχείο</b><small>Εισήγαγε το κλειδί της κοινότητας από το 🔐.</small></div></div>';return null}host.innerHTML='<div class="ith518FileCard"><span class="ico">🔓</span><div class="meta"><b>Αποκρυπτογράφηση στη συσκευή…</b></div></div>';try{const blob=await actualBlob(m),url=URL.createObjectURL(blob);host.dataset.objectUrl=url;return Object.assign({},m,{url,encrypted_v249518:false,kind:m.original_kind,mime_type:m.original_type,filename:m.original_name})}catch(e){host.innerHTML='<div class="ith518FileCard"><span class="ico">⚠️</span><div class="meta"><b>Δεν άνοιξε το κρυπτογραφημένο αρχείο</b><small>'+esc(e.message)+'</small></div></div>';return null}}
function rail(mid,hasMedia){const b=(a,icon,label,title=label)=>`<button data-ith518-action="${a}" data-mid="${esc(mid)}" title="${esc(title)}"><span class="ith518RailIcon">${icon}</span><span class="ith518RailLabel">${esc(label)}</span></button>`;return `<aside class="ith518Rail">${b('heart','♡','Καρδιά')}${b('reply','↩','Απάντηση')}${hasMedia?b('share','📤','Κοινοποίηση','Κοινοποίηση αρχείου')+b('download','⬇','Λήψη','Λήψη αρχείου')+b('full','⛶','Οθόνη','Πλήρης οθόνη'):b('share','📤','Κοινοποίηση','Κοινοποίηση ως αρχείο')}${b('more','⋯','Επιλογές','Περισσότερα')}</aside>`}
function mediaInner(m){const u=mediaUrl(m),k=mediaKind(m),n=mediaName(m);if(k==='video')return `<video controls playsinline preload="metadata" src="${esc(u)}" aria-label="${esc(n)}"></video>`;if(k==='photo')return `<img loading="lazy" src="${esc(u)}" alt="${esc(n)}">`;if(k==='audio')return `<audio controls preload="metadata" src="${esc(u)}"></audio>`;return `<div class="ith518FileCard"><span class="ico">📄</span><div class="meta"><b>${esc(n)}</b><small>${esc(mediaMime(m))}</small></div></div>`}
async function renderOne(m){let parsed=parseMessage(m.text),body=parsed.body,secure=false;try{const d=await decryptText(m.text);if(d){secure=true;try{parsed=parseMessage(d.text);body=parsed.body}catch(_e){body=d.text;parsed={body,media:null,reply:null}}}}catch(e){body='🔒 Κρυπτογραφημένο μήνυμα — λείπει ή είναι διαφορετικό το κλειδί.';secure=true}const mid=String(m.message_id||'');const mine=String(m.sender_id||'')===device();const av=String(m.avatar||m.photo||'');const has=!!parsed.media;const reply=parsed.reply;const html=`<article class="ith518Msg ${mine?'mine':''}" data-mid="${esc(mid)}"><button class="ith518Avatar" data-ith518-avatar="${esc(m.sender_id||'')}" data-name="${esc(m.nickname||'Μέλος')}">${av?`<img src="${esc(fullUrl(av))}" alt="">`:esc(initials(m.nickname))}</button><div class="ith518Bubble"><div class="ith518MsgTop"><b>${esc(m.nickname||'Μέλος')}</b>${secure?'<span class="ith518SecureMark">🔐 AES</span>':''}<time>${esc(dateText(m.created_at))}</time></div>${reply?`<div class="ith518ReplyQuote"><b>${esc(reply.nickname||'Μέλος')}</b> · ${esc(String(reply.text||'').slice(0,180))}</div>`:''}${body?`<div class="ith518Text">${esc(body)}</div>`:''}${has?`<div class="ith518MediaWrap" data-media-host="${esc(mid)}"><div class="ith518MediaStage">${parsed.media.encrypted_v249518?'<div class="ith518FileCard"><span class="ico">🔒</span><div class="meta"><b>Κρυπτογραφημένο αρχείο</b><small>Αποκρυπτογραφείται μόνο στη συσκευή.</small></div></div>':mediaInner(parsed.media)}</div>${rail(mid,true)}</div>`:`<div class="ith518TextActions"><button data-ith518-action="heart" data-mid="${esc(mid)}">♡ Καρδιά</button><button data-ith518-action="reply" data-mid="${esc(mid)}">↩ Απάντηση</button><button data-ith518-action="share" data-mid="${esc(mid)}">📤 Αρχείο</button><button data-ith518-action="more" data-mid="${esc(mid)}">⋯</button></div>`}</div></article>`;return{html,parsed:Object.assign(parsed,{body}),message:m,mid}}
async function loadMessages(){if(!active()||loading)return false;loading=true;const box=$('spaceMsgs');if(!box){loading=false;return false}box.classList.add('ith518Messages');box.innerHTML='<div class="card">Φόρτωση μηνυμάτων…</div>';try{const d=await api('/api/messages?room_id='+encodeURIComponent(room())+'&channel='+encodeURIComponent(channel())+'&since=0&limit=300');lastMessages=[];const chunks=[];for(const m of (d.messages||[])){const x=await renderOne(m);lastMessages.push(x);chunks.push(x.html)}box.innerHTML=chunks.join('')||'<div class="card">Ξεκίνα τη συνομιλία της κοινότητας.</div>';for(const x of lastMessages){if(x.parsed.media?.encrypted_v249518){const host=box.querySelector('[data-media-host="'+CSS.escape(x.mid)+'"] .ith518MediaStage');if(host){const mm=await materializeEncryptedMedia(x.parsed.media,host);if(mm){x.parsed.media=mm;host.innerHTML=mediaInner(mm)}}}}box.scrollTop=box.scrollHeight;return false}catch(e){box.innerHTML='<div class="card">Δεν φορτώθηκαν τα μηνύματα: '+esc(e.message)+'</div>';return false}finally{loading=false}}
function findMsg(mid){return lastMessages.find(x=>x.mid===String(mid))}
function setReply(x){replyTo=x?{message_id:x.mid,nickname:x.message.nickname||'Μέλος',text:String(x.parsed.body||mediaName(x.parsed.media)||'Αρχείο').slice(0,180)}:null;const b=$('ith517ReplyBox');if(!b)return;if(!replyTo){b.style.display='none';b.classList.remove('ith518ReplyActive');b.innerHTML='';return}b.classList.add('ith518ReplyActive');b.innerHTML='<span>↩</span><span class="text"><b>'+esc(replyTo.nickname)+'</b> · '+esc(replyTo.text)+'</span><button data-ith518-cancel-reply>×</button>';b.style.display='flex'}
async function sendText(){const input=$('spaceInput');const text=String(input?.value||'').trim();if(!text||!active())return false;input.value='';try{let payload;if(lockEnabled()){const plain=JSON.stringify({body:text,reply_to:replyTo});payload=await encryptText(plain)}else payload=JSON.stringify({body:text,reply_to:replyTo});await window.sendMessagePayload(channel(),payload);setReply(null);await loadMessages();return false}catch(e){input.value=text;toast('Δεν στάλθηκε: '+e.message,7000);return false}}
async function sendEncryptedFile(file,requested){if(!active())return false;if(file.size>64*1024*1024){toast('Για κρυπτογραφημένο αρχείο το όριο είναι 64 MB. Κάνε πρώτα συμπίεση ή απενεργοποίησε προσωρινά την κλειδαριά.',8000);return false}try{toast('Κρυπτογράφηση αρχείου στη συσκευή…',7000);const plain=new Uint8Array(await file.arrayBuffer()),z=await cryptBytes(plain),ki=await keyInfo();const pack={v:249518,alg:'A256GCM',kid:ki.fingerprint.slice(0,16),iv:z.iv,ct:z.ct,original_name:file.name,original_type:file.type||'application/octet-stream',original_kind:requested};const encryptedFile=new File([enc.encode(JSON.stringify(pack))],file.name+'.ithenc',{type:'application/x-ithaki-encrypted'});const up=await window.uploadWithProgress(encryptedFile,'file',true);const media={url:up.url||up.file_url,filename:encryptedFile.name,mime_type:'application/x-ithaki-encrypted',kind:'file',size:encryptedFile.size,encrypted_v249518:true,original_name:file.name,original_type:file.type||'application/octet-stream',original_kind:requested,kid:pack.kid};const caption=prompt('Λεζάντα — προαιρετικά:','')||'';await window.sendMessagePayload(channel(),JSON.stringify({body:caption,reply_to:replyTo,media}));setReply(null);toast('Το κρυπτογραφημένο αρχείο στάλθηκε.');await loadMessages();return false}catch(e){toast('Δεν στάλθηκε το κρυπτογραφημένο αρχείο: '+e.message,8000);return false}}
function openFull(x){const m=x?.parsed?.media;if(!m)return;const k=mediaKind(m);if(k==='file')return downloadMedia(m);closeFull();const d=document.createElement('div');d.id='ith518Full';d.className='ith518Full';d.innerHTML=`<div class="ith518FullHead"><button data-ith518-full-close>‹</button><b>${esc(mediaName(m))}</b><button data-ith518-full-share>📤</button><button data-ith518-full-close>×</button></div><div class="ith518FullBody">${mediaInner(m)}</div>`;document.body.appendChild(d);d.querySelectorAll('[data-ith518-full-close]').forEach(b=>b.onclick=closeFull);d.querySelector('[data-ith518-full-share]').onclick=()=>shareMedia(m);try{if(k==='video'&&d.requestFullscreen)d.requestFullscreen().catch(()=>{})}catch(e){}}
function closeFull(){try{if(document.fullscreenElement)document.exitFullscreen().catch(()=>{})}catch(e){}$('ith518Full')?.remove()}
function panel(title,html){closePanel();const d=document.createElement('div');d.id='ith518Panel';d.className='ith518Panel';d.innerHTML=`<div class="ith518PanelHead"><button data-ith518-panel-back>‹</button><b>${esc(title)}</b><button data-ith518-panel-close>×</button></div><div class="ith518PanelBody">${html}</div>`;document.body.appendChild(d);d.querySelector('[data-ith518-panel-back]').onclick=closePanel;d.querySelector('[data-ith518-panel-close]').onclick=closePanel;return d}
function closePanel(){const p=$('ith518Panel');if(p)p.remove()}
async function more(x){const role=(S().spaces||[]).find(s=>String(s.subroom_id)===sid())?.role||'member';const p=panel('Επιλογές μηνύματος',`<div class="ith518Grid"><button class="ith518Choice" data-m="reply">↩ Απάντηση</button><button class="ith518Choice" data-m="share">📤 Κοινοποίηση αρχείου</button>${x.parsed.media?'<button class="ith518Choice" data-m="download">⬇ Λήψη</button><button class="ith518Choice" data-m="full">⛶ Πλήρης οθόνη</button>':''}<button class="ith518Choice" data-m="report">⚠️ Αναφορά</button>${['creator','moderator'].includes(role)?'<button class="ith518Choice gold" data-m="pin">📌 Καρφίτσωμα</button>':''}</div>`);p.querySelectorAll('[data-m]').forEach(b=>b.onclick=async()=>{const a=b.dataset.m;closePanel();if(a==='reply')setReply(x);if(a==='share')x.parsed.media?shareMedia(x.parsed.media):shareTextFile(x.parsed.body||x.message.text,'ITHAKI_message_'+x.mid+'.txt');if(a==='download')downloadMedia(x.parsed.media);if(a==='full')openFull(x);if(a==='report'){const reason=prompt('Λόγος αναφοράς:')||'';if(reason)try{await api('/api/rooms/report_message',{method:'POST',body:JSON.stringify({room_id:room(),subroom_id:sid(),message_id:x.mid,reporter_id:device(),reason})});toast('Η αναφορά στάλθηκε.')}catch(e){toast(e.message)}}if(a==='pin')try{await api('/api/rooms/pin',{method:'POST',body:JSON.stringify({room_id:room(),subroom_id:sid(),message_id:x.mid,pinned_by:device(),note:''})});toast('Το μήνυμα καρφιτσώθηκε.')}catch(e){toast(e.message)}})}
async function actionClick(b){const x=findMsg(b.dataset.mid),a=b.dataset.ith518Action;if(!x)return;if(a==='share'){const now=Date.now(),key=String(x.mid||'');if(key===lastShareMidV249526R6&&now-lastShareAtV249526R6<1400)return;lastShareMidV249526R6=key;lastShareAtV249526R6=now}if(a==='heart')try{const d=await api('/api/reactions/toggle',{method:'POST',body:JSON.stringify({target_id:'space_message:'+x.mid,device_id:device(),emoji:'❤️',nickname:nickname()})});b.textContent=d.active?'♥':'♡'}catch(e){toast(e.message)};if(a==='reply')setReply(x);if(a==='share')x.parsed.media?shareMedia(x.parsed.media):shareTextFile(x.parsed.body||x.message.text,'ITHAKI_message_'+x.mid+'.txt');if(a==='download')downloadMedia(x.parsed.media);if(a==='full')openFull(x);if(a==='more')more(x)}
function avatarMenu(id,name){const self=String(id)===device();const p=panel('Μέλος κοινότητας',`<div class="ith518Card" style="text-align:center"><div class="ith518Avatar" style="width:72px;height:72px;margin:auto">${esc(initials(name))}</div><h3>${esc(self?'Εσύ':name)}</h3></div><div class="ith518Grid">${!self?'<button class="ith518Choice green" data-av="dm">💬 Προσωπικό μήνυμα</button>':''}<button class="ith518Choice" data-av="profile">👤 Προφίλ μέλους</button><button class="ith518Choice" data-av="close">✓ Κλείσιμο</button></div>`);p.querySelectorAll('[data-av]').forEach(b=>b.onclick=()=>{const a=b.dataset.av;closePanel();if(a==='dm'){const f=I().openDMWith||I().startDM;if(typeof f==='function')f.call(I(),id)}if(a==='profile'){const f=I().openMemberProfile||I().openProfileFor;if(typeof f==='function')f.call(I(),id);else toast('Προφίλ: '+name)}})}
async function generateKey(){const raw=crypto.getRandomValues(new Uint8Array(32));localStorage.setItem(keyStore(),b64(raw));localStorage.setItem(lockStore(),'1');toast('Δημιουργήθηκε νέο κοινόχρηστο κλειδί AES‑256. Στείλε το αρχείο κλειδιού μόνο σε έμπιστα μέλη.');openLockPanel()}
async function keyPackageBlob(){const k=await keyInfo();if(!k.raw.length)throw Error('Δεν υπάρχει κλειδί.');const data={type:'OK_ITHAKI_COMMUNITY_KEY',version:249518,algorithm:'AES-256-GCM',room_id:room(),subroom_id:sid(),community:String($('spaceTitle')?.textContent||'Κοινότητα'),key_b64:b64(k.raw),fingerprint:k.fingerprint,created_at:new Date().toISOString()};return new Blob([JSON.stringify(data,null,2)],{type:'application/x-ithaki-key+json'})}
async function shareKey(){try{const blob=await keyPackageBlob();await shareBlob(blob,'ITHAKI_COMMUNITY_'+sid()+'.ithkey','application/x-ithaki-key+json');toast('Το πραγματικό αρχείο κλειδιού κοινοποιήθηκε. Χρησιμοποίησε έμπιστο κανάλι.')}catch(e){toast(e.message)}}
async function importKeyFile(){let inp=$('ith518KeyInput');if(!inp){inp=document.createElement('input');inp.id='ith518KeyInput';inp.type='file';inp.accept='.ithkey,application/json,application/x-ithaki-key+json';inp.style.display='none';document.body.appendChild(inp)}inp.value='';inp.onchange=async()=>{try{const f=inp.files?.[0];if(!f)return;const o=JSON.parse(await f.text());const raw=unb64(o.key_b64||'');if(raw.length!==32)throw Error('Το αρχείο δεν περιέχει κλειδί AES‑256.');if(o.room_id&&String(o.room_id)!==room())throw Error('Το κλειδί ανήκει σε άλλο δωμάτιο server.');if(o.subroom_id&&String(o.subroom_id)!==sid()&&!confirm('Το κλειδί γράφει διαφορετική κοινότητα. Να εισαχθεί παρ’ όλα αυτά;'))return;localStorage.setItem(keyStore(),b64(raw));localStorage.setItem(lockStore(),'1');toast('Το κλειδί εισήχθη και η κλειδαριά ενεργοποιήθηκε.');closePanel();await loadMessages()}catch(e){toast('Δεν εισήχθη το κλειδί: '+e.message,8000)}};inp.click()}
async function fingerprintQr(){try{const k=await keyInfo();if(!k.raw.length)throw Error('Δημιούργησε ή εισήγαγε πρώτα κλειδί.');const verify='OK-ITHAKI|V249518|'+room()+'|'+sid()+'|SHA256:'+k.fingerprint;const p=panel('QR επαλήθευσης κλειδιού',`<div class="ith518Card"><p>Το QR περιέχει μόνο το αποτύπωμα. Δεν περιέχει το μυστικό κλειδί.</p><img class="ith518Qr" src="/api/pair/qr?text=${encodeURIComponent(verify)}" alt="QR αποτυπώματος"><div class="ith518KeyFp">${esc(k.fingerprint)}</div><button class="ith518Choice" id="ith518ShareQr" style="width:100%;margin-top:10px">📤 Κοινοποίηση QR ως PNG</button></div>`);p.querySelector('#ith518ShareQr').onclick=async()=>{const blob=await fetchBlob('/api/pair/qr?text='+encodeURIComponent(verify));await shareBlob(blob,'ITHAKI_KEY_FINGERPRINT_QR.png','image/png')}}catch(e){toast(e.message)}}
async function openLockPanel(){const has=!!getKeyB64(),on=lockEnabled();let fp='—';if(has)try{fp=(await keyInfo()).fingerprint}catch(e){}const p=panel('🔐 Προστασία κοινότητας',`<div class="ith518Card"><b>Κοινόχρηστη κρυπτογράφηση AES‑256‑GCM</b><p>Διαφορετική από την προσωπική E2EE: όλα τα έμπιστα μέλη χρησιμοποιούν το ίδιο μυστικό κλειδί. Το κλειδί μένει τοπικά στη συσκευή.</p><div class="ith518KeyFp">${esc(fp)}</div></div><div class="ith518Grid"><button class="ith518Choice ${on?'green':''}" data-key="toggle">${on?'🔒 Κλειδαριά ενεργή':'🔓 Ενεργοποίηση κλειδαριάς'}</button><button class="ith518Choice gold" data-key="generate">🗝️ Έκδοση νέου κλειδιού</button><button class="ith518Choice" data-key="share">📤 Αποστολή αρχείου κλειδιού</button><button class="ith518Choice" data-key="import">📥 Εισαγωγή .ithkey</button><button class="ith518Choice" data-key="qr">▦ QR αποτυπώματος</button><button class="ith518Choice" data-key="remove">🗑️ Αφαίρεση από συσκευή</button></div><div class="ith518Card"><small>Για αρχεία πάνω από 64 MB, απενεργοποίησε την κλειδαριά ή συμπίεσέ τα πρώτα. Το μυστικό κλειδί δεν αποστέλλεται στον server για δημιουργία QR.</small></div>`);p.querySelectorAll('[data-key]').forEach(b=>b.onclick=async()=>{const a=b.dataset.key;if(a==='toggle'){if(!has)return generateKey();localStorage.setItem(lockStore(),on?'0':'1');closePanel();openLockPanel()}if(a==='generate'&&confirm('Νέο κλειδί σημαίνει ότι τα παλιότερα κρυπτογραφημένα μηνύματα θέλουν το παλιό κλειδί. Συνέχεια;'))generateKey();if(a==='share')shareKey();if(a==='import')importKeyFile();if(a==='qr')fingerprintQr();if(a==='remove'&&confirm('Να αφαιρεθεί το κλειδί μόνο από αυτή τη συσκευή;')){localStorage.removeItem(keyStore());localStorage.removeItem(lockStore());closePanel();toast('Το κλειδί αφαιρέθηκε από τη συσκευή.');loadMessages()}})}
async function openPolls(){const d=await api('/api/rooms/polls_v249516?room_id='+encodeURIComponent(room())+'&subroom_id='+encodeURIComponent(sid())+'&device_id='+encodeURIComponent(device()));let html='<button class="ith518Choice green" id="ith518CreatePoll" style="width:100%;margin-bottom:10px">＋ Νέα ψηφοφορία από μέλος</button>';html+=(d.polls||[]).map(p=>`<div class="ith518Card"><b>${esc(p.question)}</b>${(p.options||[]).map(o=>`<button class="ith518PollOption ${p.my_option_id===o.option_id?'mine':''}" data-poll="${esc(p.poll_id)}" data-opt="${esc(o.option_id)}"><span>${esc(o.label)}</span><b>${Number(o.votes||0)}${p.my_option_id===o.option_id?' ✓':''}</b></button>`).join('')}<button class="ith518TextActions" data-share-poll="${esc(p.poll_id)}" style="border:0;background:transparent;color:#fff">📤 Κοινοποίηση ως αρχείο</button></div>`).join('')||'<div class="ith518Card">Δεν υπάρχουν ψηφοφορίες.</div>';const p=panel('🗳️ Ψηφοφορίες',html);p.querySelector('#ith518CreatePoll').onclick=createPoll;p.querySelectorAll('[data-poll][data-opt]').forEach(b=>b.onclick=async()=>{try{await api('/api/rooms/polls/vote_v249516',{method:'POST',body:JSON.stringify({room_id:room(),subroom_id:sid(),device_id:device(),poll_id:b.dataset.poll,option_id:b.dataset.opt})});openPolls()}catch(e){toast(e.message)}});p.querySelectorAll('[data-share-poll]').forEach(b=>b.onclick=()=>{const poll=(d.polls||[]).find(x=>String(x.poll_id)===b.dataset.sharePoll);if(poll)shareTextFile([poll.question,...poll.options.map(o=>'- '+o.label+' ('+o.votes+')')].join('\n'),'ITHAKI_poll_'+poll.poll_id+'.txt')})}
async function createPoll(){const q=prompt('Ερώτηση ψηφοφορίας:')||'';if(!q)return;const opts=(prompt('Επιλογές χωρισμένες με |:','Ναι | Όχι')||'').split('|').map(x=>x.trim()).filter(Boolean).slice(0,9);if(opts.length<2)return toast('Χρειάζονται τουλάχιστον δύο επιλογές.');try{await api('/api/rooms/polls/create_v249518',{method:'POST',body:JSON.stringify({room_id:room(),subroom_id:sid(),device_id:device(),nickname:nickname(),question:q,options:opts})});toast('Η ψηφοφορία δημοσιεύτηκε από μέλος.');openPolls()}catch(e){toast(e.message)}}
function universalShare(){const o=I();if(window.__ITHAKI_V249526R3_OWNER__)return;if(o.__v249518ShareInstalled)return;o.__v249518ShareInstalled=true;const old=o.share;if(typeof old==='function')o.__v249518OldShare=old;o.share=async function(url,text){const u=String(url||'');try{if(u.includes('/api/pair/qr')){const blob=await fetchBlob(u);return shareBlob(blob,'ITHAKI_QR.png','image/png')}if(/\/api\/media\/file\/|\.(mp4|mov|webm|3gp|jpe?g|png|gif|webp|pdf|docx?|xlsx?|pptx?|zip|rar|7z|mp3|m4a|wav|ogg)(?:[?#]|$)/i.test(u)){const n=decodeURIComponent(u.split('/').pop().split('?')[0])||'OK_ITHAKI_file',br=window.AndroidBridge||window.OKITHAKI_ANDROID;if(br&&typeof br.shareRemoteFileV249521==='function'&&/^https?:/i.test(fullUrl(u))){const rr=String(br.shareRemoteFileV249521(fullUrl(u),n,'application/octet-stream')||'');if(/^(ok|queued)/i.test(rr))return true}const blob=await fetchBlob(u);return shareBlob(blob,n,blob.type)}return shareTextFile([text||'',u].filter(Boolean).join('\n'),'ITHAKI_share.txt')}catch(e){toast('Η κοινοποίηση απέτυχε: '+e.message);return false}};o.shareActualFileV249518=shareMedia;o.shareTextAsFileV249518=shareTextFile;
if(typeof o.openSharePostV249433==='function'&&!o.openSharePostV249433.__v249518){const op=o.openSharePostV249433;o.openSharePostV249433=function(id){window.__ITHAKI_SHARE_POST_ID_V249518=String(id||'');return op.apply(this,arguments)};o.openSharePostV249433.__v249518=true}
if(typeof o.externalSharePostV249433==='function'){o.externalSharePostV249433=function(){const id=String(window.__ITHAKI_SHARE_POST_ID_V249518||'');return id&&typeof o.sharePost==='function'?o.sharePost(id):shareTextFile('OK ITHAKI','ITHAKI_share.txt')}}
if(typeof o.shareQRSite==='function'){o.shareQRSite=async function(){const site=location.origin;const blob=await fetchBlob('/api/pair/qr?text='+encodeURIComponent('ITHAKI_SITE:'+site));return shareBlob(blob,'ITHAKI_SITE_QR.png','image/png')}}}
function intercept(e){const b=e.target?.closest?.('[data-ith518-action],[data-ith518-avatar],[data-ith518-cancel-reply],[data-ith516-action],button[title="Ιδιωτική προστασία"],#ith517MembersBar [data-member-id],#ithQrShare387');if(!b)return;if(b.id==='ithQrShare387'){e.preventDefault();e.stopImmediatePropagation();const img=document.querySelector('#ithCreatorQrModal387 img');if(img?.src)fetchBlob(img.src).then(x=>shareBlob(x,'ITHAKI_CREATOR_QR.png','image/png')).catch(x=>toast(x.message));return}if(b.hasAttribute('data-ith518-action')){e.preventDefault();e.stopImmediatePropagation();actionClick(b);return}if(b.hasAttribute('data-ith518-avatar')){e.preventDefault();e.stopImmediatePropagation();avatarMenu(b.dataset.ith518Avatar,b.dataset.name||'Μέλος');return}if(b.hasAttribute('data-ith518-cancel-reply')){e.preventDefault();setReply(null);return}if(b.matches('#ith517MembersBar [data-member-id]')){e.preventDefault();e.stopImmediatePropagation();avatarMenu(b.dataset.memberId,String(b.textContent||'Μέλος').trim());return}if(b.getAttribute('title')==='Ιδιωτική προστασία'){e.preventDefault();e.stopImmediatePropagation();openLockPanel();return}if(b.dataset.ith516Action==='polls'){e.preventDefault();e.stopImmediatePropagation();openPolls().catch(x=>toast(x.message));return}}
function fileCapture(e){const t=e.target;if(!active()||!lockEnabled()||!['ith517SpaceFileInput','ith517SpacePhotoInput','ith517SpaceVideoInput'].includes(t?.id))return;const f=t.files?.[0];if(!f)return;e.stopImmediatePropagation();e.preventDefault();const kind=t.id.includes('Video')?'video':t.id.includes('Photo')?'photo':'file';sendEncryptedFile(f,kind);try{t.value=''}catch(x){}}
function ensureAvatarEscape(){document.querySelectorAll('#memberMenu.show,#memberMenu.fullAvatarMenuV249231').forEach(m=>{if(m.querySelector('[data-ith518-avatar-escape]'))return;const b=document.createElement('button');b.type='button';b.dataset.ith518AvatarEscape='1';b.className='icon';b.textContent='‹';b.title='Επιστροφή';b.style.cssText='position:sticky;top:4px;left:4px;z-index:50';b.onclick=e=>{e.preventDefault();e.stopPropagation();m.classList.remove('show','fullAvatarMenuV249231')};m.prepend(b)})}
function install(){addCss();universalShare();const o=I();o.loadSpaceMessages=loadMessages;o.loadSpaceMessagesV249518=loadMessages;window.loadSpaceMessages=loadMessages;o.sendSpaceText=sendText;window.sendSpaceText=sendText;o.openCommunitySharedLockV249518=openLockPanel;o.openCommunityPollsV249518=openPolls;o.shareCommunityKeyV249518=shareKey;o.importCommunityKeyV249518=importKeyFile;o.closeCommunityFullV249518=closeFull;try{const u=new URL(location.href);if(u.searchParams.get('v')!=='249524'){u.searchParams.set('v',(window.ITHAKI_ACTIVE_VERSION||'249526r10f37f1f2'));history.replaceState(null,'',u.pathname+'?'+u.searchParams.toString()+u.hash)}}catch(e){}document.addEventListener('click',intercept,true);document.addEventListener('change',fileCapture,true);new MutationObserver(()=>{clearTimeout(install._m);install._m=setTimeout(()=>{ensureAvatarEscape();const box=$('spaceMsgs');if(active()&&box&&(!box.classList.contains('ith518Messages')||box.querySelector(':scope > .bubble,:scope > .messageMediaV249464')))loadMessages()},70)}).observe(document.body,{subtree:true,childList:true});ensureAvatarEscape();if(active())loadMessages();try{localStorage.setItem('ith_frontend_build','V249518-community-video-keys-universal-file-share');document.documentElement.setAttribute('data-ithaki-v249518','community-video-keys-universal-file-share')}catch(e){}}
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',install,{once:true});else install();window.addEventListener('ithaki:page-changed',()=>setTimeout(()=>{if(active())loadMessages()},80));
})();
