<?php
/**
 * /api/trial/status — Device-fingerprint trial tracker.
 *
 * Anti-reinstall strategy: the 30-day countdown is anchored to the
 * first time the SERVER sees a given hardware_id. Uninstalling and
 * reinstalling the app doesn't reset the clock because ANDROID_ID
 * survives reinstalls (until factory reset).
 *
 * POST body:
 *   { hardware_id: string (required),
 *     mac_address?: string, model?: string, app_version?: string }
 *
 * Response:
 *   { hardware_id, first_seen_at, last_seen_at,
 *     trial_days, days_used, days_remaining, trial_expired,
 *     is_premium, premium_expiry }
 *
 * Premium flag is at the DEVICE level (admin can flip a device to
 * premium when the user redeems a key on the website). The frontend
 * OR-combines this with the logged-in user's `is_expired` check.
 */

if (!defined('TRIAL_DAYS_DEFAULT')) {
    define('TRIAL_DAYS_DEFAULT', 30);
}

function ensure_device_trials_table(): void {
    static $done = false;
    if ($done) return;
    $done = true;
    $sql = <<<SQL
CREATE TABLE IF NOT EXISTS `device_trials` (
  `hardware_id`     VARCHAR(128) NOT NULL PRIMARY KEY,
  `mac_address`     VARCHAR(32)           DEFAULT NULL,
  `model`           VARCHAR(128)          DEFAULT NULL,
  `app_version`     VARCHAR(32)           DEFAULT NULL,
  `first_seen_at`   VARCHAR(40)  NOT NULL,
  `last_seen_at`    VARCHAR(40)  NOT NULL,
  `is_premium`      TINYINT(1)   NOT NULL DEFAULT 0,
  `premium_expiry`  VARCHAR(40)           DEFAULT NULL,
  INDEX `ix_device_trials_first_seen` (`first_seen_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
SQL;
    db()->exec($sql);
}

function _trial_days_between(string $iso, DateTime $now): int {
    try {
        $start = new DateTime($iso);
    } catch (Throwable $e) {
        return 0;
    }
    $secs = $now->getTimestamp() - $start->getTimestamp();
    if ($secs <= 0) return 0;
    return (int)floor($secs / 86400);
}

function route_trial_status(): void {
    ensure_device_trials_table();
    $b = read_json_body();

    $hw = isset($b['hardware_id']) ? trim((string)$b['hardware_id']) : '';
    if ($hw === '' || strlen($hw) < 4 || strlen($hw) > 128) {
        json_error(400, 'hardware_id is required (4–128 chars)');
    }
    $mac   = isset($b['mac_address']) ? substr((string)$b['mac_address'], 0, 32) : null;
    $model = isset($b['model'])       ? substr((string)$b['model'], 0, 128)      : null;
    $ver   = isset($b['app_version']) ? substr((string)$b['app_version'], 0, 32) : null;

    $now     = new DateTime('now', new DateTimeZone('UTC'));
    $now_iso = now_iso();

    $sel = db()->prepare('SELECT * FROM device_trials WHERE hardware_id = ?');
    $sel->execute([$hw]);
    $row = $sel->fetch();

    if (!$row) {
        $ins = db()->prepare(
            'INSERT INTO device_trials
             (hardware_id, mac_address, model, app_version, first_seen_at, last_seen_at, is_premium, premium_expiry)
             VALUES (?, ?, ?, ?, ?, ?, 0, NULL)'
        );
        $ins->execute([$hw, $mac, $model, $ver, $now_iso, $now_iso]);
        $row = [
            'hardware_id'    => $hw,
            'mac_address'    => $mac,
            'model'          => $model,
            'app_version'    => $ver,
            'first_seen_at'  => $now_iso,
            'last_seen_at'   => $now_iso,
            'is_premium'     => 0,
            'premium_expiry' => null,
        ];
    } else {
        $up = db()->prepare(
            'UPDATE device_trials
             SET last_seen_at = ?,
                 mac_address  = COALESCE(?, mac_address),
                 model        = COALESCE(?, model),
                 app_version  = COALESCE(?, app_version)
             WHERE hardware_id = ?'
        );
        $up->execute([$now_iso, $mac, $model, $ver, $hw]);
    }

    $trial_days = TRIAL_DAYS_DEFAULT;
    $days_used  = _trial_days_between($row['first_seen_at'], $now);
    $days_remaining = max(0, $trial_days - $days_used);
    $trial_expired  = $days_remaining <= 0;

    $is_premium = !empty($row['is_premium']);
    $premium_expiry = $row['premium_expiry'] ?? null;
    if ($is_premium && $premium_expiry) {
        try {
            $dt = new DateTime($premium_expiry);
            if ($dt->getTimestamp() < $now->getTimestamp()) {
                $is_premium = false;
                db()->prepare('UPDATE device_trials SET is_premium = 0 WHERE hardware_id = ?')
                    ->execute([$hw]);
            }
        } catch (Throwable $e) {
            /* keep is_premium as-is */
        }
    }

    send_json([
        'hardware_id'    => $hw,
        'first_seen_at'  => $row['first_seen_at'],
        'last_seen_at'   => $now_iso,
        'trial_days'     => $trial_days,
        'days_used'      => $days_used,
        'days_remaining' => $days_remaining,
        'trial_expired'  => $trial_expired,
        'is_premium'     => $is_premium,
        'premium_expiry' => $premium_expiry,
    ]);
}


// ────────────────────────────────────────────────────────────────────
// Admin endpoints — flip is_premium when an external license key
// is redeemed, list all known devices, or forget a device.
// ────────────────────────────────────────────────────────────────────

function _augment_device_row(array $row): array {
    $now = new DateTime('now', new DateTimeZone('UTC'));
    $trial_days = TRIAL_DAYS_DEFAULT;
    $days_used  = _trial_days_between($row['first_seen_at'], $now);
    return [
        'hardware_id'    => $row['hardware_id'],
        'mac_address'    => $row['mac_address']    ?? null,
        'model'          => $row['model']          ?? null,
        'app_version'    => $row['app_version']    ?? null,
        'first_seen_at'  => $row['first_seen_at'],
        'last_seen_at'   => $row['last_seen_at']   ?? $row['first_seen_at'],
        'is_premium'     => !empty($row['is_premium']),
        'premium_expiry' => $row['premium_expiry'] ?? null,
        'note'           => $row['note']           ?? null,
        'days_used'      => $days_used,
        'days_remaining' => max(0, $trial_days - $days_used),
        'trial_expired'  => ($trial_days - $days_used) <= 0,
    ];
}

function route_admin_list_device_trials(): void {
    require_admin();
    ensure_device_trials_table();
    // Add `note` column lazily for older schemas.
    try {
        db()->exec("ALTER TABLE device_trials ADD COLUMN note VARCHAR(500) NULL");
    } catch (Throwable $e) {
        /* column already exists */
    }
    $limit = isset($_GET['limit']) ? max(1, min(2000, (int)$_GET['limit'])) : 500;
    $stmt = db()->prepare(
        'SELECT * FROM device_trials ORDER BY last_seen_at DESC LIMIT ' . $limit
    );
    $stmt->execute();
    $rows = $stmt->fetchAll();
    $out = [];
    foreach ($rows as $r) $out[] = _augment_device_row($r);
    send_json($out);
}

function route_admin_patch_device_trial(string $hw): void {
    require_admin();
    ensure_device_trials_table();
    try {
        db()->exec("ALTER TABLE device_trials ADD COLUMN note VARCHAR(500) NULL");
    } catch (Throwable $e) { /* exists */ }

    $sel = db()->prepare('SELECT * FROM device_trials WHERE hardware_id = ?');
    $sel->execute([$hw]);
    $row = $sel->fetch();
    if (!$row) json_error(404, 'device_trial not found');

    $b = read_json_body();
    $sets   = [];
    $params = [];
    if (array_key_exists('is_premium', $b)) {
        $sets[]   = 'is_premium = ?';
        $params[] = !empty($b['is_premium']) ? 1 : 0;
    }
    if (array_key_exists('premium_expiry', $b)) {
        $val = $b['premium_expiry'];
        if ($val === '' || $val === null) {
            $sets[]   = 'premium_expiry = NULL';
        } else {
            try { new DateTime($val); }
            catch (Throwable $e) { json_error(400, 'Invalid premium_expiry'); }
            $sets[]   = 'premium_expiry = ?';
            $params[] = (string)$val;
        }
    }
    if (array_key_exists('note', $b)) {
        $sets[]   = 'note = ?';
        $params[] = is_null($b['note']) ? null : substr((string)$b['note'], 0, 500);
    }
    if (empty($sets)) json_error(400, 'Nothing to update');
    $params[] = $hw;
    $sql = 'UPDATE device_trials SET ' . implode(', ', $sets) . ' WHERE hardware_id = ?';
    db()->prepare($sql)->execute($params);

    $sel->execute([$hw]);
    $fresh = $sel->fetch();
    send_json(_augment_device_row($fresh));
}

function route_admin_delete_device_trial(string $hw): void {
    require_admin();
    ensure_device_trials_table();
    $stmt = db()->prepare('DELETE FROM device_trials WHERE hardware_id = ?');
    $stmt->execute([$hw]);
    if ($stmt->rowCount() === 0) json_error(404, 'device_trial not found');
    send_json(['ok' => true]);
}
