<?php
/**
 * weather.php — Weather widget page for the Tivi app's Weather menu.
 *
 * The Tivi app's Weather menu is a WebView. Point it at:
 *     {panel_url}weather.php
 *
 * Adapted from the XCIPTV-3004 backdrop widget (assets/backdrop/tmdb.html + tmdb.js):
 *   - Live clock (time + date)
 *   - 3-day weather forecast (open-meteo API) with icons, temps, rain %
 *   - Auto-detects location via ipwhois.app
 *   - TV-friendly: large text, D-pad friendly, no scroll needed
 *
 * IMPORTANT: The WebView JS must NOT call external APIs directly — cross-origin
 * fetch() to ipwhois.app / open-meteo.com is blocked by CORS in the WebView,
 * which shows "Weather unavailable". Instead, this page proxies both calls
 * server-side (same-origin), so the JS only fetches {panel_url}weather.php?loc=1
 * and {panel_url}weather.php?forecast=lat,lon.
 *
 * No API key required. Fully automatic.
 */

include('includes/functions.php');

if (!headers_sent()) {
    header_remove('Cache-Control');
    header('Cache-Control: no-store, no-cache, private, must-revalidate, max-age=0', true);
    header('CDN-Cache-Control: no-store', true);
    header('Pragma: no-cache', true);
    header('Expires: 0', true);
}

/* ------------------------------------------------------------------ */
/* Server-side proxy endpoints (same-origin, no CORS issues)          */
/* ------------------------------------------------------------------ */

function http_get_json(string $url, int $timeout = 10): ?array {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => $timeout,
        CURLOPT_CONNECTTIMEOUT => $timeout,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_USERAGENT      => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15',
        CURLOPT_HTTPHEADER     => ['Accept: application/json'],
    ]);
    $raw = curl_exec($ch);
    $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($raw === false || $code < 200 || $code >= 300) {
        return null;
    }
    $j = json_decode($raw, true);
    return is_array($j) ? $j : null;
}

$action = $_GET['action'] ?? '';

if ($action === 'loc') {
    // Return the DEVICE's location, not the server's.
    // The panel server sees the device's IP via REMOTE_ADDR; query ipwhois
    // with that IP so we geolocate the actual viewer, not the server host.
    header('Content-Type: application/json; charset=UTF-8');
    $clientIp = $_SERVER['REMOTE_ADDR'] ?? '';
    // Respect X-Forwarded-For only if behind a trusted proxy (optional).
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $xff = trim(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]);
        if (filter_var($xff, FILTER_VALIDATE_IP)) {
            $clientIp = $xff;
        }
    }
    $j = http_get_json('http://ip-api.com/json/' . rawurlencode($clientIp) . '?fields=status,lat,lon,city,countryCode');
    if ($j && isset($j['status']) && $j['status'] === 'success' && isset($j['lat'])) {
        echo json_encode([
            'success' => true,
            'latitude'  => (float) $j['lat'],
            'longitude' => (float) $j['lon'],
            'city'      => $j['city'] ?? 'Unknown',
            'country'   => $j['countryCode'] ?? 'US',
        ]);
    } else {
        echo json_encode(['success' => false, 'error' => 'location']);
    }
    exit;
}

if ($action === 'forecast') {
    // Return the 3-day forecast (proxied from open-meteo).
    header('Content-Type: application/json; charset=UTF-8');
    $lat = (float) ($_GET['lat'] ?? 0);
    $lon = (float) ($_GET['lon'] ?? 0);
    if ($lat == 0 && $lon == 0) {
        echo json_encode(['success' => false, 'error' => 'coords']);
        exit;
    }
    $url = 'https://api.open-meteo.com/v1/forecast?latitude=' . $lat
         . '&longitude=' . $lon
         . '&daily=temperature_2m_max,temperature_2m_min,weathercode,precipitation_probability_max,wind_speed_10m_max,wind_direction_10m_dominant,sunrise,sunset'
         . '&timezone=auto';
    $j = http_get_json($url);
    if ($j && isset($j['daily'])) {
        echo json_encode(['success' => true, 'daily' => $j['daily']]);
    } else {
        echo json_encode(['success' => false, 'error' => 'data']);
    }
    exit;
}

/* ------------------------------------------------------------------ */
/* Page HTML                                                          */
/* ------------------------------------------------------------------ */

$css = <<<'CSS'
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%}
body{background:linear-gradient(160deg,#0b1020 0%,#101a33 55%,#0b1020 100%);color:#fff;font-family:'Segoe UI',Roboto,Arial,sans-serif;overflow:hidden;display:flex;align-items:center;justify-content:center}
.wrap{width:100%;max-width:1500px;padding:4vh 4vw;text-align:center}
.clock{font-size:clamp(40px,12vh,120px);font-weight:800;line-height:1;letter-spacing:2px;text-shadow:0 4px 30px rgba(0,0,0,.5)}
.date{font-size:clamp(18px,4.5vh,44px);font-weight:600;margin-top:1vh;opacity:.85;letter-spacing:1px}
.city{font-size:clamp(16px,3.5vh,34px);font-weight:500;margin-top:1vh;opacity:.7}
.weather{display:flex;justify-content:center;gap:.8vw;margin-top:4vh;flex-wrap:nowrap}
.day{background:rgba(255,255,255,.07);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.12);border-radius:2vh;padding:1.4vh .8vw;min-width:0;flex:1 1 0;text-align:center;transition:transform .2s}
.day:focus,.day:hover{outline:none;transform:scale(1.05);background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.35)}
.day .dow{font-size:clamp(12px,2.2vh,22px);font-weight:600;opacity:.85}
.day .ico{font-size:clamp(22px,4.5vh,48px);margin:.8vh 0 .4vh}
.day .temp{font-size:clamp(20px,4vh,44px);font-weight:800}
.day .lo{font-size:clamp(11px,1.9vh,19px);color:#9aa7c0;margin-top:.2vh}
.day .rain{font-size:clamp(11px,1.9vh,19px);color:#7ec8ff;margin-top:.4vh}
.day .wind{font-size:clamp(10px,1.7vh,17px);color:#c9b8ff;margin-top:.3vh}
.day .sun{font-size:clamp(9px,1.5vh,15px);color:rgba(236,233,248,.6);margin-top:.3vh}
.hint{position:fixed;bottom:2vh;left:0;right:0;text-align:center;font-size:clamp(12px,2vh,20px);opacity:.4;letter-spacing:1px}
.discord-btn{display:inline-flex;align-items:center;gap:.8rem;margin-top:3vh;padding:1.2vh 2.4vw;border-radius:2rem;background:#5865F2;color:#fff;font-size:clamp(16px,3.2vh,30px);font-weight:700;text-decoration:none;cursor:pointer;outline:none;border:none;transition:transform .2s,background .2s}
.discord-btn:focus,.discord-btn:hover{outline:none;transform:scale(1.05);background:#4752c4;box-shadow:0 0 0 3px rgba(88,101,242,.5)}
.discord-btn .ic{font-size:1.2em}
CSS;

$js = <<<'JS'
(function(){
var LANG="en-US",F_COUNTRIES=["US","LR","MM","BS","KY"],lat=null,lon=null,city="",country="";
function getIcon(c){return c===0?"☀️":c<=3?"⛅":c<=48?"🌫️":c<=67?"🌧️":c<=77?"❄️":c<=82?"🌧️":c<=99?"⛈️":"☁️"}
function esc(s){var d=document.createElement("div");d.textContent=s==null?"":String(s);return d.innerHTML}
function fmt(t){return F_COUNTRIES.indexOf(country)>=0?Math.round(9*t/5+32)+"°F":Math.round(t)+"°C"}
function fetchT(u,t){var a=new AbortController,o=setTimeout(function(){a.abort()},t||8000);return fetch(u,{signal:a.signal}).then(function(r){clearTimeout(o);if(!r.ok)throw new Error("HTTP "+r.status);return r.json()}).catch(function(e){clearTimeout(o);throw e})}
function clock(){var n=new Date,t=n.toLocaleTimeString(LANG,{hour:"numeric",minute:"2-digit",hour12:true}),d=n.toLocaleDateString(LANG,{weekday:"long",month:"long",day:"numeric"});var e=document.getElementById("t");if(e)e.textContent=t;var f=document.getElementById("d");if(f)f.textContent=d}
function render(a){var w=document.getElementById("w");w.innerHTML="";for(var i=0;i<7;i++){var n=new Date;n.setDate(n.getDate()+i);var dow=i===0?"Today":n.toLocaleDateString(LANG,{weekday:"short"}),mx=a.daily.temperature_2m_max?.[i],mn=a.daily.temperature_2m_min?.[i],cd=a.daily.weathercode?.[i]??0,rn=a.daily.precipitation_probability_max?.[i]??0,ws=a.daily.wind_speed_10m_max?.[i],sr=a.daily.sunrise?.[i],ss=a.daily.sunset?.[i];var d=document.createElement("div");d.className="day";d.tabIndex=0;d.innerHTML='<div class="dow">'+esc(dow)+'</div><div class="ico">'+getIcon(cd)+'</div><div class="temp">'+(mx!=null?fmt(mx):"--")+'</div><div class="lo">'+(mn!=null?"L "+fmt(mn):"")+'</div><div class="rain">'+(rn>=10?"💧 "+rn+"%":"")+'</div><div class="wind">'+(ws!=null?"💨 "+Math.round(ws)+" km/h":"")+'</div><div class="sun">'+(sr?'☀️ '+sr.slice(11,16)+' · 🌙 '+ss.slice(11,16):"")+'</div>';w.appendChild(d)}var c=document.getElementById("c");if(c)c.textContent=city}
function start(){clock();setInterval(clock,1000);
function useCoords(la,lo,cityName,countryCode){lat=Number(la);lon=Number(lo);city=cityName||"Unknown";country=countryCode||"US";var c=document.getElementById("c");if(c)c.textContent=city;return fetchT("weather.php?action=forecast&lat="+lat+"&lon="+lon)}
function useIp(){return fetchT("weather.php?action=loc").then(function(j){if(!j||!j.success)throw new Error("loc");return useCoords(j.latitude,j.longitude,j.city,j.country)})}
function show(a){if(!a||!a.success||!a.daily)throw new Error("data");render(a);setInterval(function(){fetchT("weather.php?action=forecast&lat="+lat+"&lon="+lon).then(function(x){if(x&&x.success)render(x)}).catch(function(){})},600000)}
function gotPos(p){var la=p.coords.latitude,lo=p.coords.longitude;return useCoords(la,lo,"","").then(show).catch(function(){return noPos()})}
function noPos(){return useIp().then(show).catch(function(){var w=document.getElementById("w");if(w)w.innerHTML='<div class="day"><div class="dow">Weather</div><div class="ico">🌦️</div><div class="temp">--</div></div>'})}
if(navigator.geolocation){navigator.geolocation.getCurrentPosition(gotPos,noPos,{enableHighAccuracy:true,timeout:8000,maximumAge:60000})}else{noPos()}
}
document.addEventListener("keydown",function(e){var a=document.activeElement,k=e.key,c=e.keyCode;if(k==="ArrowRight"||c===39){e.preventDefault();var n=a&&a.nextElementSibling;if(n)n.focus()}else if(k==="ArrowLeft"||c===37){e.preventDefault();var p=a&&a.previousElementSibling;if(p)p.focus()}});
start();
})();
JS;

echo '<!doctype html><html lang="en"><head><meta charset="utf-8">'
   . '<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">'
   . '<title>Weather</title><style>' . $css . '</style></head><body>'
   . '<div class="wrap">'
   . '<div class="clock" id="t">--:--</div>'
   . '<div class="date" id="d"></div>'
   . '<div class="city" id="c"></div>'
   . '<div class="weather" id="w"></div>'
   . '</div>'
   . '<div class="hint">◀ ▶ to navigate</div>'
   . '<script>' . $js . '</script></body></html>';
