<?php
session_start();
ini_set('log_errors',     '1');
ini_set('display_startup_errors', 1);
ini_set('error_reporting', E_ALL);
ini_set('error_log',      __DIR__ . '/error.log');
// Force Eastern Time for all date() calls
date_default_timezone_set('America/New_York');
// ─── LOGIN PROTECTION (with logging) ─────────────────────────────────────────

// List of valid users → password hashes
$valid_users = [
  'A' => '5db1fee4b5703808c48078a76768b155b421b210c0761cd6a5d223f4d99f1eaa',
  'J' => '5db1fee4b5703808c48078a76768b155b421b210c0761cd6a5d223f4d99f1eaa',
];
// ─── Upload-only password ────────────────────────────────────────────────────
$uploadPasswordHash = '$2y$10$1oc.yun9HAiaZWmAsIXjXe9C6VszDH9iIgzlBesScpXb1bCxrTxUS';

// Handle logout
if (isset($_GET['logout'])) {
    $user = $_SESSION['username'] ?? 'unknown';
    log_action("LOGOUT: {$user}");
    unset($_SESSION['authenticated'], $_SESSION['username']);
    session_destroy();
    header('Location: index.php');
    exit;
}

// If not authenticated, show login form
if (empty($_SESSION['authenticated'])) {
    $error = '';
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $user = trim($_POST['username'] ?? '');
        $pass = $_POST['password']   ?? '';

        // Check credentials
        if (isset($valid_users[$user]) 
            && hash('sha256', $pass) === $valid_users[$user]
        ) {
            $_SESSION['authenticated'] = true;
            $_SESSION['username']      = $user;
            log_action("LOGIN SUCCESS: {$user}");
            header('Location: index.php');
            exit;
        } else {
            log_action("LOGIN FAILURE: {$user}");
            $error = 'Invalid username or password.';
        }
    }
    // — Simple login page —
    ?>
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Login — Mickey’s Gallery</title>
      <style>
        body { display:flex; height:100vh; align-items:center; justify-content:center;
               font-family:Arial,sans-serif; background:#f0f0f0; margin:0 }
        .box { background:#fff; padding:2rem; border-radius:6px;
               box-shadow:0 2px 8px rgba(0,0,0,.1); width:300px; }
        input { width:100%; padding:.75rem; margin-top:.5rem; font-size:1rem; }
        button { margin-top:1rem; padding:.75rem 1.5rem; width:100%; }
        .error { color:#c00; margin-top:.5rem; }
      </style>
    </head>
    <body>
      <div class="box">
        <h2>Login to Mickey’s Gallery</h2>
        <?php if($error): ?><p class="error"><?= $error ?></p><?php endif; ?>
        <form method="post">
          <input type="text" name="username" placeholder="Username" required autofocus>
          <input type="password" name="password" placeholder="Password" required>
          <button type="submit">Log In</button>
        </form>
      </div>
	  <script>
	      // ─── Disable right-click & DevTools ─────────────────────────────────────────
    document.addEventListener('contextmenu', e => e.preventDefault());
    document.addEventListener('keydown', e => {
        if (e.keyCode === 123 || // F12
            (e.ctrlKey && e.shiftKey && (e.keyCode === 73
                || e.keyCode === 74)) ||      // Ctrl+Shift+I/J
            (e.ctrlKey && e.keyCode === 85)                        // Ctrl+U
        ) {
            e.preventDefault();
        }
    });
</script>
    </body>
    </html>
    <?php
    exit; // stop here until they log in
}
// ─── Assign persistent visitor ID ─────────────────────────────────────────────
if (!isset($_COOKIE['visitor_id'])) {
    $visitor_id = bin2hex(random_bytes(16));
    setcookie('visitor_id', $visitor_id, time()+365*24*60*60, '/', '', true, true);
} else {
    $visitor_id = $_COOKIE['visitor_id'];
}

// ─── LOGGING HELPER ────────────────────────────────────────────────────────────
function get_geolocation(string $ip): string {
    static $inMemory = [];
    if (isset($inMemory[$ip])) {
        return $inMemory[$ip];
    }
    $cacheDir  = __DIR__ . '/geo_cache';
    $cacheFile = "$cacheDir/$ip.json";
    if (file_exists($cacheFile) && time() - filemtime($cacheFile) < 86400) {
        $raw = file_get_contents($cacheFile);
    } else {
        if (!is_dir($cacheDir)) mkdir($cacheDir, 0755, true);
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            => "http://ip-api.com/json/$ip?fields=status,city,regionName,country,countryCode",
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CONNECTTIMEOUT => 2,
            CURLOPT_TIMEOUT        => 3,
        ]);
        $raw = curl_exec($ch);
        curl_close($ch);
        if ($raw !== false) file_put_contents($cacheFile, $raw);
    }
    if ($raw) {
        $data = json_decode($raw, true);
        if (!empty($data['status']) && $data['status']==='success') {
            $loc = "{$data['city']}, {$data['regionName']}, {$data['country']} {$data['countryCode']}";
            return $inMemory[$ip] = $loc;
        }
    }
    return $inMemory[$ip] = 'Location Not Found';
}
/**
 * Turn a 2-letter ISO country code into the 🇦🇺 style flag emoji.
 */
function getFlagEmoji(string $code): string {
    $code = strtoupper(substr($code, 0, 2));
    $base = 0x1F1E6;  // Unicode codepoint for Regional Indicator Symbol Letter A

    // If mb_chr isn't available, just return the code
    if (!function_exists('mb_chr')) {
        return $code;
    }

    $firstCp  = $base + (ord($code[0]) - ord('A'));
    $secondCp = $base + (ord($code[1]) - ord('A'));

    return mb_chr($firstCp, 'UTF-8') . mb_chr($secondCp, 'UTF-8');
}

function log_action(string $action): void {
    $visitor_id = $_COOKIE['visitor_id'] ?? 'unknown';
    $user       = $_SESSION['username']   ?? 'guest';
    $visitor    = "{$visitor_id} (Username: {$user})";

    $ip   = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
    $ua   = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
    // JUST log the raw geo (no emoji!)
    $loc  = get_geolocation($ip);  // e.g. "Newark, New Jersey, United States US"

    $time = date('Y-m-d H:i:s');
    $line = implode(' | ', [
      $visitor,
      $ip,
      $ua,
      $loc,
      $action,
      $time,
    ]) . "\n";

    file_put_contents(__DIR__ . '/logs.txt', $line, FILE_APPEND|LOCK_EX);
}


// Log page views
if ($_SERVER['REQUEST_METHOD']==='GET' && !isset($_GET['upload'])) {
    log_action('VISIT index.php');
    if (!isset($_SESSION['logged_visit'])) {
        log_action('VISIT');
        $_SESSION['logged_visit'] = true;
    }
}
if (isset($_GET['log_view'])) {
    log_action('VIEW ' . urldecode($_GET['log_view']));
    exit;
}
// ─── AUTH: Upload Form Unlock ────────────────────────────────────────────────
if (isset($_POST['upload_password'])) {
    if (password_verify($_POST['upload_password'], $uploadPasswordHash)) {
        $_SESSION['upload_auth'] = true;
        log_action('LOGIN upload');
    } else {
        $upload_error = '❌ Incorrect upload password.';
        log_action('FAILED LOGIN upload');
    }
}

// Optional “log out of upload” link
if (isset($_GET['logout_upload'])) {
    unset($_SESSION['upload_auth']);
    header('Location: index.php');
    exit;
}

// ─── VirusTotal helpers ───────────────────────────────────────────────────────
define('VT_API_KEY', '78e2de724beffa237867f5125b113a7aed68e08391e40d9c7bf3072f841d175d');

function scanWithVirusTotal(string $filePath): ?string {
    $file = curl_file_create($filePath);
    $ch = curl_init('https://www.virustotal.com/api/v3/files');
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER    => ["x-apikey: " . VT_API_KEY],
        CURLOPT_RETURNTRANSFER=> true,
        CURLOPT_POST          => true,
        CURLOPT_POSTFIELDS    => ['file' => $file],
    ]);
    $resp = curl_exec($ch);
    curl_close($ch);
    if (!$resp) return null;
    $data = json_decode($resp, true);
    return $data['data']['id'] ?? null;
}

// re‐analysis endpoint
function rescanWithVirusTotal(string $fileHash): ?string {
    global $virusTotalApiKey;
    $ch = curl_init("https://www.virustotal.com/api/v3/files/{$fileHash}/analyse");
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER    => [
            "x-apikey: {$virusTotalApiKey}",
            "Content-Type: application/json",
        ],
        CURLOPT_POST          => true,
        CURLOPT_RETURNTRANSFER=> true,
    ]);
    $resp = curl_exec($ch);
    curl_close($ch);
    if (!$resp) return null;
    $data = json_decode($resp, true);
    return $data['data']['id'] ?? null;
}

function getVirusTotalReport(string $analysisId): ?string {
    $ch = curl_init("https://www.virustotal.com/api/v3/analyses/{$analysisId}");
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER    => ["x-apikey: " . VT_API_KEY],
        CURLOPT_RETURNTRANSFER=> true,
    ]);
    $resp = curl_exec($ch);
    curl_close($ch);
    $data = json_decode($resp, true);
    return $data['meta']['file_info']['sha256'] ?? null;
}

// ─── Handle upload + VT scan ─────────────────────────────────────────────────
$uploadDir     = __DIR__ . '/uploads/';
$statusMessage = '';
$virusTotalLink= '';

if (isset($_FILES['upload'])) {
    $messages = [];
    foreach ($_FILES['upload']['error'] as $i => $err) {
        $name = basename($_FILES['upload']['name'][$i]);
        if ($err !== UPLOAD_ERR_OK) {
            $messages[] = "<p style='color:red;'>Error uploading <strong>$name</strong> (code $err).</p>";
            continue;
        }

        $tmp  = $_FILES['upload']['tmp_name'][$i];
        $dest = $uploadDir . $name;

        // 1) initial VT scan
        $analysisId = scanWithVirusTotal($tmp);
        if (!$analysisId) {
            $messages[] = "<p style='color:red;'>VT scan failed for <strong>$name</strong>. <a href='https://www.virustotal.com/gui/home/upload' target='_blank'>Manual scan</a>.</p>";
            continue;
        }

// 2) poll for report (up to 30s)
$fileHash  = null;
$timeout   = 30;    // seconds total
$interval  = 3;     // seconds between tries
$startTime = time();

while (time() - $startTime < $timeout) {
    if ($h = getVirusTotalReport($analysisId)) {
        $fileHash = $h;
        break;
    }
    sleep($interval);
}

if (!$fileHash) {
    $statusMessage = '<p style="color:red;">VT report unavailable after 30s.</p>';
            continue;
        }

        // 3) optional re-scan if too old (reuse your last_scanned logic here…)
$scanTimestampFile = __DIR__ . '/uploads/' . $name . '.last_scanned';
$doRescan = false;
if (file_exists($scanTimestampFile)) {
    // how many seconds since last scan?
    $age = time() - (int)file_get_contents($scanTimestampFile);
    if ($age > 12 * 3600) { // older than 12 hours
        $doRescan = true;
    }
} else {
    // never scanned before
    $doRescan = true;
}

if ($doRescan) {
    // trigger a fresh VT analysis
    $newAnalysisId = rescanWithVirusTotal($fileHash);
    if ($newAnalysisId) {
        // poll for the new report
        for ($i = 0; $i < 5; $i++) {
            sleep(2);
            if ($h2 = getVirusTotalReport($newAnalysisId)) {
                $fileHash = $h2;
                break;
            }
        }
    }
}

// record that we just scanned
file_put_contents($scanTimestampFile, (string)time());
        // 4) move into uploads
        if (!move_uploaded_file($tmp, $dest)) {
            $messages[] = "<p style='color:red;'>Failed to save <strong>$name</strong>.</p>";
            continue;
        }

        // 5) log & build link
        log_action("Uploaded photo $name");
        $vtLink = "https://www.virustotal.com/gui/file/$fileHash";
        $messages[] = 
          "<p style='color:green;'>Uploaded <strong>$name</strong>. "
         . "<a href='$vtLink' target='_blank'>View VT report</a></p>";
    }

    // show all results
    $statusMessage = implode("\n", $messages);
}



// ─── Decide sort mode ────────────────────────────────────────────────────────
$valid = ['upload_desc','upload_asc','taken_desc','taken_asc'];
$mode  = $_GET['sort'] ?? 'upload_desc';
if (! in_array($mode, $valid, true)) {
    $mode = 'upload_desc';
}

// ─── Grab all images ─────────────────────────────────────────────────────────
$uploadDir = __DIR__ . '/uploads/';
$files = glob($uploadDir . '*.{jpg,jpeg,png,gif}', GLOB_BRACE);

// ─── Sort ────────────────────────────────────────────────────────────────────
usort($files, function($a, $b) use ($mode) {
    switch ($mode) {
        case 'upload_desc':
            return filemtime($b) <=> filemtime($a);
        case 'upload_asc':
            return filemtime($a) <=> filemtime($b);

        case 'taken_desc':
            $ea = @exif_read_data($a)['DateTimeOriginal'] ?? '';
            $eb = @exif_read_data($b)['DateTimeOriginal'] ?? '';
            $ta = $ea ? strtotime($ea) : 0;
            $tb = $eb ? strtotime($eb) : 0;
            return $tb <=> $ta;
        case 'taken_asc':
            $ea = @exif_read_data($a)['DateTimeOriginal'] ?? '';
            $eb = @exif_read_data($b)['DateTimeOriginal'] ?? '';
            $ta = $ea ? strtotime($ea) : 0;
            $tb = $eb ? strtotime($eb) : 0;
            return $ta <=> $tb;
        default:
            return 0;
    }
});
?>

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Mickey’s Gallery</title>
<!-- iOS home-screen icon -->
<link rel="apple-touch-icon" sizes="180x180" href="/favicon.png">
<!-- PNG alternative (if you used a .png file) -->
<link rel="icon" href="/favicon.png" type="image/png">

    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: Arial, sans-serif; background-color: #323639; color: #333; padding: 20px; text-align: center; }
        h1 { font-size: 2.5rem; margin-bottom: 20px; }
#gallery {
  width: 100%;
  column-width: 220px;
  column-gap: 1em;
  margin: 30px auto;
}

/* base sizing for a column */
.grid-sizer,
.thumb {
  width: 220px;         /* choose your ideal column width */
  margin-bottom: 1em;   /* vertical gutter */
}

.thumb {
  /* nothing else needed – Masonry will position these */
}
.cat-photo {
  display: block;
  width: 100%;
  margin-bottom: 1em;
  border-radius: 10px;
  transition: transform .3s;
  cursor: zoom-in;
}
.cat-photo:hover {
  transform: scale(1.02);
}


        .upload-form { margin-top: 40px; padding: 10px; background-color: #fff; border: 1px solid #ddd; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); }
        input[type="file"], input[type="submit"] { padding: 10px; border-radius: 5px; }
        input[type="submit"] { background-color: #28a745; color: white; cursor: pointer; }
        input[type="submit"]:hover { background-color: #218838; }
        button { padding: 10px 20px; background-color: #000000; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; }
        button:hover { background-color: #000000; }
#overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.8);
    display: none; /* Ensures it stays hidden initially */
    z-index: 999;
}

#overlay.active {
    display: block; /* Only shows when zooming */
}
.cat-photo.expanded {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    max-width: 90vw;
    max-height: 90vh;
    width: auto;
    height: auto;
    object-fit: contain;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
    cursor: zoom-out;
    z-index: 1000; /* Ensures image stays above the overlay */
}
.sort-buttons {
  display: flex;               
  justify-content: center;     /* center items */
  gap: 1em;                    /* space between buttons */
  margin: 20px 0;
}

.sort-buttons button {
    background-color: #000000;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    transition: background-color 0.3s;
}

.sort-buttons button:hover {
    background-color: #000000;
}
button.active {
  background-color: #000000;
}

	</style>
</head>
<body>
<div style="text-align:right;margin-bottom:10px;">
  <a href="index.php"><button>Home</button></a>
  <a href="admin.php"><button>Admin Panel</button></a>
  <a href="?logout=1"><button>Logout</button></a>
</div>
<h1 style="color: white;">
  <img
    src="/favicon.png"
    width="96"
    height="96"
    style="vertical-align: middle; margin-right: 0;"
  >
  Mickey’s Gallery
  <img
    src="/favicon.png"
    width="96"
    height="96"
    style="vertical-align: middle; margin-left: 0;"
  >
</h1>


<?php if ($statusMessage): ?>
  <?= $statusMessage /* already contains your <p>…</p> */ ?>
<?php endif; ?>


<?php if (empty($_SESSION['upload_auth'])): ?>
  <!-- padlock form to unlock uploads -->
  <form method="post" style="margin-bottom:1em;">
    <input 
      type="password" 
      name="upload_password" 
      placeholder="Enter upload password" 
      required 
      style="padding:.5em;margin-right:.5em;"
    >
    <button type="submit">Unlock</button>
  </form>
  <?php if (!empty($upload_error)): ?>
    <div style="color:red; margin-bottom:1em;">
      <?= htmlspecialchars($upload_error) ?>
    </div>
  <?php endif; ?>
<?php else: ?>
  <!-- show your real upload form -->
  <form method="post" enctype="multipart/form-data" class="upload-form">
    <input type="file" name="upload[]" multiple required>
    <input type="submit" name="upload" value="Upload">
	<p>
  <a 
    href="?logout_upload=1" 
    style="text-decoration:none; color:#3498db; /* match your buttons */ padding:8px 16px; display:inline-block;"
  >
    🔒 Lock
  </a>
</p>
  </form>
<?php endif; ?>
<br>

<div style="text-align:center; margin-bottom:10px;">
  <button
    onclick="location.href='?sort=upload_desc'"
    class="<?= $mode==='upload_desc'?'active':'' ?>"
  >Newest Upload</button>

  <button
    onclick="location.href='?sort=taken_desc'"
    class="<?= $mode==='taken_desc'?'active':'' ?>"
  >Newest Date Taken</button>

  <button
    onclick="location.href='?sort=upload_asc'"
    class="<?= $mode==='upload_asc'?'active':'' ?>"
  >Oldest Upload</button>

  <button
    onclick="location.href='?sort=taken_asc'"
    class="<?= $mode==='taken_asc'?'active':'' ?>"
  >Oldest Date Taken</button>
</div>



<div id="overlay"></div>
<div id="gallery">
  <?php foreach ($files as $path): 
    $file = basename($path);
    $url  = "uploads/".rawurlencode($file);
  ?>
    <div class="thumb">
      <img src="<?= $url ?>" class="cat-photo" alt="">
    </div>
  <?php endforeach; ?>
</div>


<script>
document.addEventListener("DOMContentLoaded", function () {
    const overlay = document.getElementById("overlay");
    const images = document.querySelectorAll(".cat-photo");

    images.forEach(image => {
        image.addEventListener("click", function () {
            if (this.classList.contains("expanded")) {
                this.classList.remove("expanded");
                overlay.classList.remove("active");
                overlay.style.display = "none"; // Hide overlay properly
            } else {
                this.classList.add("expanded");
                overlay.classList.add("active");
                overlay.style.display = "block"; // Show overlay only when zooming
            }
        });
    });

    overlay.addEventListener("click", function () {
        images.forEach(image => image.classList.remove("expanded"));
        overlay.classList.remove("active");
        overlay.style.display = "none"; // Hide overlay when clicking outside image
    });
});

    // ─── Disable right-click & DevTools ─────────────────────────────────────────
    document.addEventListener('contextmenu', e => e.preventDefault());
    document.addEventListener('keydown', e => {
        if (e.keyCode === 123 || // F12
            (e.ctrlKey && e.shiftKey && (e.keyCode === 73
                || e.keyCode === 74)) ||      // Ctrl+Shift+I/J
            (e.ctrlKey && e.keyCode === 85)                        // Ctrl+U
        ) {
            e.preventDefault();
        }
    });
</script>
<!-- masonry pkgd bundle -->
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<script>
  var grid = document.querySelector('#gallery');

  // insert a sizing element for % positioning
  var sizer = document.createElement('div');
  sizer.className = 'grid-sizer';
  grid.insertBefore(sizer, grid.firstChild);

  new Masonry( grid, {
    itemSelector: '.thumb',
    columnWidth: '.grid-sizer',    // use the sizer for column width
    gutter: 16,                    // horizontal gutter (px)
    percentPosition: true,         // enable % positioning
    horizontalOrder: true          // enforce row-first placement
  });
</script>

</body>
</html>