<?php
/**
 * POST /api/admin/seed_demo_data.php
 * Body (JSON): { confirm: true }
 *
 * Admin-only. Resets and reseeds a self-contained demo dataset so the whole
 * system (marketplace, cart, checkout, pantry, loyalty, business dashboard,
 * reports, notifications) can be exercised end-to-end without hand-creating
 * data through the UI.
 *
 * SAFE TO RE-RUN: every seeded account uses an @ragreen-demo.test email, so
 * this script only ever touches rows it created itself - it never looks at
 * or deletes real accounts (including your admin account). Running it again
 * wipes the previous demo batch and creates a fresh one.
 *
 * All seeded accounts share the password: Demo@1234
 */

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../includes/response.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/loyalty.php';
require_once __DIR__ . '/../includes/notifications.php';
require_once __DIR__ . '/../includes/settings.php';

only_post_allowed();
require_login();
require_role(['admin']);

$input = get_json_input();
if (empty($input['confirm'])) {
    send_error('Send {"confirm": true} to run the seeder - this resets any previous demo batch.', 422);
}

const DEMO_DOMAIN = '@ragreen-demo.test';
const DEMO_PASSWORD = 'Demo@1234';

$pdo = Database::connect();

try {
    $pdo->beginTransaction();

    // ---------- 1. Wipe any previous demo batch (dependency-safe order) ----------
    $stmt = $pdo->query("SELECT id FROM users WHERE email LIKE '%" . DEMO_DOMAIN . "'");
    $demoUserIds = array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));

    if ($demoUserIds) {
        $ids = implode(',', $demoUserIds);

        $stmt = $pdo->query("SELECT id FROM products WHERE owner_id IN ($ids)");
        $demoProductIds = array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));
        $pids = $demoProductIds ? implode(',', $demoProductIds) : '0';

        // order_items reference products/users with ON DELETE RESTRICT, so these
        // must go before orders/products/users can be deleted.
        $pdo->exec("DELETE FROM order_items WHERE product_id IN ($pids) OR seller_id IN ($ids)");
        $pdo->exec("DELETE FROM orders WHERE buyer_id IN ($ids)");
        $pdo->exec("DELETE FROM cart_items WHERE user_id IN ($ids) OR product_id IN ($pids)");
        $pdo->exec("DELETE FROM reports WHERE reported_by IN ($ids) OR product_id IN ($pids) OR reported_user_id IN ($ids)");
        $pdo->exec("DELETE FROM products WHERE owner_id IN ($ids)"); // cascades product_images
        $pdo->exec("DELETE FROM users WHERE id IN ($ids)"); // cascades profiles, pantry, loyalty, notifications
    }

    // ---------- 2. Category lookup (seeded by schema.sql) ----------
    $catStmt = $pdo->query('SELECT id, name FROM categories');
    $cat = [];
    foreach ($catStmt->fetchAll() as $row) {
        $cat[$row['name']] = (int) $row['id'];
    }

    $passwordHash = password_hash(DEMO_PASSWORD, PASSWORD_BCRYPT);

    $insertUser = $pdo->prepare(
        'INSERT INTO users (email, password_hash, phone, account_type, email_verified_at) VALUES (?, ?, ?, ?, NOW())'
    );
    $insertPersonal = $pdo->prepare('INSERT INTO personal_profiles (user_id, full_name, city) VALUES (?, ?, ?)');
    $insertBusiness = $pdo->prepare('INSERT INTO business_profiles (user_id, business_name, category, contact_person, city, trial_ends_at) VALUES (?, ?, ?, ?, ?, ?)');
    $insertLoyaltyRow = $pdo->prepare('INSERT INTO loyalty_points (user_id, points_balance) VALUES (?, 0)');

    function seed_user(PDO $pdo, $insertUser, $passwordHash, string $localPart, string $phone, string $accountType): int
    {
        $insertUser->execute([$localPart . DEMO_DOMAIN, $passwordHash, $phone, $accountType]);
        return (int) $pdo->lastInsertId();
    }

    // ---------- 3. Business sellers ----------
    $businesses = [
        ['local' => 'greengrocer',  'name' => 'Green Grocer Beirut',   'category' => 'Grocery',   'city' => 'Beirut',   'phone' => '+9611000001'],
        ['local' => 'sunrisebakery','name' => 'Sunrise Bakery',        'category' => 'Bakery',    'city' => 'Beirut',   'phone' => '+9611000002'],
        ['local' => 'dairyfresh',   'name' => 'Dairy Fresh Co',        'category' => 'Dairy',     'city' => 'Jounieh',  'phone' => '+9611000003'],
        ['local' => 'cornerpantry', 'name' => 'Corner Pantry Market',  'category' => 'Packaged Goods', 'city' => 'Saida', 'phone' => '+9611000004'],
    ];
    $bizId = [];
    $trialDays = (int) get_setting($pdo, 'business_trial_days', '90');
    $trialEndsAt = date('Y-m-d', strtotime("+$trialDays days"));
    foreach ($businesses as $b) {
        $id = seed_user($pdo, $insertUser, $passwordHash, $b['local'], $b['phone'], 'business');
        $insertBusiness->execute([$id, $b['name'], $b['category'], 'Demo Contact', $b['city'], $trialEndsAt]);
        $insertLoyaltyRow->execute([$id]);
        $bizId[$b['local']] = $id;
    }

    // ---------- 4. Personal buyers ----------
    $personals = [
        ['local' => 'layla',  'name' => 'Layla Haddad', 'city' => 'Beirut',  'phone' => '+9613000001'],
        ['local' => 'omar',   'name' => 'Omar Fares',   'city' => 'Beirut',  'phone' => '+9613000002'],
        ['local' => 'nadine', 'name' => 'Nadine Khoury','city' => 'Jounieh', 'phone' => '+9613000003'],
        ['local' => 'karim',  'name' => 'Karim Aziz',   'city' => 'Saida',   'phone' => '+9613000004'],
        ['local' => 'rana',   'name' => 'Rana Saleh',   'city' => 'Beirut',  'phone' => '+9613000005'],
        ['local' => 'tarek',  'name' => 'Tarek Nassar', 'city' => 'Tripoli', 'phone' => '+9613000006'],
    ];
    $personId = [];
    foreach ($personals as $p) {
        $id = seed_user($pdo, $insertUser, $passwordHash, $p['local'], $p['phone'], 'personal');
        $insertPersonal->execute([$id, $p['name'], $p['city']]);
        $insertLoyaltyRow->execute([$id]);
        $personId[$p['local']] = $id;
    }

    // ---------- 5. Products ----------
    $insertProduct = $pdo->prepare('
        INSERT INTO products (owner_id, category_id, name, description, quantity, original_price, selling_price, expiry_date, location, status)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ');
    $today = new DateTime('today');
    $d = fn($days) => (clone $today)->modify("$days days")->format('Y-m-d');

    // [owner key, category name, name, description, qty, original, selling, expiry offset days, location, status]
    $products = [
        [$bizId['greengrocer'], 'Fruits & Vegetables', 'Organic Tomatoes', 'A bit soft but great for sauce.', 15, 3.00, 1.50, $d(10), 'Beirut', 'active'],
        [$bizId['greengrocer'], 'Fruits & Vegetables', 'Fresh Cucumbers', 'Crisp, from this week\'s harvest.', 2, 2.00, 1.00, $d(2), 'Beirut', 'active'],
        [$bizId['greengrocer'], 'Fruits & Vegetables', 'Bell Peppers Mix', 'Red, yellow, green mix.', 8, 4.00, 2.50, $d(5), 'Beirut', 'active'],
        [$bizId['greengrocer'], 'Fruits & Vegetables', 'Overripe Bananas', 'Perfect for banana bread.', 6, 1.50, 0.50, $d(-1), 'Beirut', 'active'],
        [$bizId['greengrocer'], 'Fruits & Vegetables', 'Zucchini Squash', 'Sold out fast!', 0, 2.50, 1.20, $d(3), 'Beirut', 'sold'],

        [$bizId['sunrisebakery'], 'Bakery', 'Sourdough Loaf', 'Baked yesterday morning.', 4, 6.00, 3.00, $d(2), 'Beirut', 'active'],
        [$bizId['sunrisebakery'], 'Bakery', 'Croissants (dozen)', 'Buttery, from this morning.', 20, 12.00, 7.00, $d(1), 'Beirut', 'active'],
        [$bizId['sunrisebakery'], 'Bakery', 'Day-Old Bagels', 'Still soft, great toasted.', 1, 5.00, 2.00, $d(3), 'Beirut', 'active'],
        [$bizId['sunrisebakery'], 'Bakery', 'Rye Bread', 'Temporarily paused listing.', 5, 5.50, 3.00, $d(7), 'Beirut', 'inactive'],
        [$bizId['sunrisebakery'], 'Bakery', 'Cinnamon Rolls', 'Six-pack, glazed.', 3, 8.00, 4.00, $d(-2), 'Beirut', 'active'],

        [$bizId['dairyfresh'], 'Dairy & Eggs', 'Whole Milk 1L', 'Best before printed on carton.', 12, 2.00, 1.20, $d(4), 'Jounieh', 'active'],
        [$bizId['dairyfresh'], 'Dairy & Eggs', 'Greek Yogurt Tubs', 'Pack of 4, plain.', 3, 5.00, 2.80, $d(2), 'Jounieh', 'active'],
        [$bizId['dairyfresh'], 'Dairy & Eggs', 'Farm Eggs (dozen)', 'Free-range, local farm.', 25, 4.00, 2.50, $d(14), 'Jounieh', 'active'],
        [$bizId['dairyfresh'], 'Dairy & Eggs', 'Cheddar Cheese Block', 'Sharp cheddar, 400g.', 2, 6.50, 4.00, $d(6), 'Jounieh', 'active'],

        [$bizId['cornerpantry'], 'Canned & Packaged', 'Canned Chickpeas', 'Case of 6 cans.', 30, 9.00, 5.00, $d(180), 'Saida', 'active'],
        [$bizId['cornerpantry'], 'Canned & Packaged', 'Pasta Penne 500g', 'Sealed, near best-by date.', 18, 2.50, 1.50, $d(365), 'Saida', 'active'],
        [$bizId['cornerpantry'], 'Beverages', 'Orange Juice Cartons', 'Pack of 3, 1L each.', 5, 7.50, 4.00, $d(8), 'Saida', 'active'],
        [$bizId['cornerpantry'], 'Beverages', 'Sparkling Water 6-pack', 'Assorted flavors.', 1, 6.00, 3.00, $d(20), 'Saida', 'active'],
    ];

    $productId = []; // name => id, for easy lookup below
    foreach ($products as $p) {
        [$ownerId, $catName, $name, $desc, $qty, $orig, $sell, $expiry, $loc, $status] = $p;
        $insertProduct->execute([$ownerId, $cat[$catName] ?? null, $name, $desc, $qty, $orig, $sell, $expiry, $loc, $status]);
        $productId[$name] = (int) $pdo->lastInsertId();
        // Mirror real listing behavior: publishing awards loyalty points.
        award_loyalty_points($pdo, $ownerId, points_per_new_listing($pdo), 'Published a new listing');
    }

    // Admin moderation example: hide one listing, notify its seller (mirrors admin/products_update_status.php)
    $pdo->prepare('UPDATE products SET status = "inactive" WHERE id = ?')->execute([$productId['Bell Peppers Mix']]);
    create_notification($pdo, $bizId['greengrocer'], 'listing_hidden', 'Your listing "Bell Peppers Mix" was hidden by an admin. Contact support if you have questions.');

    // ---------- 6. Pantry items ----------
    $insertPantry = $pdo->prepare('INSERT INTO pantry_items (user_id, product_name, quantity, expiry_date) VALUES (?, ?, ?, ?)');
    $pantryItems = [
        [$personId['layla'], 'Milk', 1, $d(1)],
        [$personId['layla'], 'Eggs', 6, $d(10)],
        [$personId['layla'], 'Leftover Rice', 2, null],
        [$personId['layla'], 'Old Yogurt', 1, $d(-1)],
        [$personId['omar'], 'Bread', 1, $d(2)],
        [$personId['omar'], 'Frozen Peas', 1, $d(60)],
    ];
    foreach ($pantryItems as $item) {
        $insertPantry->execute($item);
    }

    // ---------- 7. Cart items (left unpurchased, for testing cart/checkout screens) ----------
    $insertCart = $pdo->prepare('INSERT INTO cart_items (user_id, product_id, quantity) VALUES (?, ?, ?)');
    $insertCart->execute([$personId['nadine'], $productId['Whole Milk 1L'], 2]);
    $insertCart->execute([$personId['nadine'], $productId['Farm Eggs (dozen)'], 1]);
    // Deliberately requests more than the current stock (2 on hand) to demo the "over stock" cart warning.
    $insertCart->execute([$personId['karim'], $productId['Cheddar Cheese Block'], 3]);

    // ---------- 8. Completed orders (mirrors orders/checkout.php: stock, points, notifications) ----------
    function seed_order(PDO $pdo, int $buyerId, array $lines, bool $autoFulfill = true): int
    {
        // $lines: [ [product_id, seller_id, quantity, unit_price], ... ]
        $total = array_sum(array_map(fn($l) => $l[2] * $l[3], $lines));

        $stmt = $pdo->prepare('INSERT INTO orders (buyer_id, total_amount, status) VALUES (?, ?, "pending")');
        $stmt->execute([$buyerId, round($total, 2)]);
        $orderId = (int) $pdo->lastInsertId();

        $sellerTotals = [];
        $orderItemIds = [];
        foreach ($lines as [$productId, $sellerId, $qty, $unitPrice]) {
            $pdo->prepare('INSERT INTO order_items (order_id, product_id, seller_id, quantity, unit_price) VALUES (?, ?, ?, ?, ?)')
                ->execute([$orderId, $productId, $sellerId, $qty, $unitPrice]);
            $orderItemIds[] = (int) $pdo->lastInsertId();

            $stockStmt = $pdo->prepare('SELECT quantity FROM products WHERE id = ?');
            $stockStmt->execute([$productId]);
            $remaining = (int) $stockStmt->fetchColumn() - $qty;
            $pdo->prepare('UPDATE products SET quantity = ?, status = ? WHERE id = ?')
                ->execute([$remaining, $remaining <= 0 ? 'sold' : 'active', $productId]);

            $sellerTotals[$sellerId]['amount'] = ($sellerTotals[$sellerId]['amount'] ?? 0) + $qty * $unitPrice;
            $sellerTotals[$sellerId]['items'] = ($sellerTotals[$sellerId]['items'] ?? 0) + $qty;
        }

        if (!$autoFulfill) {
            // Leave this one pending on purpose - so the demo data actually shows
            // off the "confirm sale" workflow instead of everything already done.
            create_notification($pdo, $buyerId, 'order_placed', "Order #$orderId placed - $" . number_format($total, 2) . ". Awaiting seller confirmation.");
            foreach ($sellerTotals as $sellerId => $s) {
                create_notification($pdo, $sellerId, 'order_pending', "New order: {$s['items']} item(s) for $" . number_format($s['amount'], 2) . " in order #$orderId. Confirm it in My Sales.");
            }
            return $orderId;
        }

        // Mirror the real fulfillment flow (mark every item fulfilled, award
        // points per item, resolve the parent order) rather than the old
        // "award everything at checkout" shortcut - keeps demo data
        // consistent with how a real sale actually completes now.
        foreach ($orderItemIds as $itemId) {
            $pdo->prepare('UPDATE order_items SET status = "fulfilled" WHERE id = ?')->execute([$itemId]);
        }
        $pdo->prepare('UPDATE orders SET status = "completed" WHERE id = ?')->execute([$orderId]);

        foreach ($lines as [$productId, $sellerId, $qty, $unitPrice]) {
            $lineTotal = $qty * $unitPrice;
            $points = (int) floor($lineTotal * points_per_dollar_spent($pdo));
            award_loyalty_points($pdo, $buyerId, $points, "Purchase fulfilled - order #$orderId");
        }

        create_notification($pdo, $buyerId, 'order_fulfilled', "Order #$orderId complete - $" . number_format($total, 2) . ".");
        foreach ($sellerTotals as $sellerId => $s) {
            create_notification($pdo, $sellerId, 'order_sold', "You sold {$s['items']} item(s) for $" . number_format($s['amount'], 2) . " in order #$orderId.");
        }

        return $orderId;
    }

    seed_order($pdo, $personId['rana'], [
        [$productId['Sourdough Loaf'], $bizId['sunrisebakery'], 2, 3.00],
        [$productId['Whole Milk 1L'], $bizId['dairyfresh'], 1, 1.20],
    ]);

    seed_order($pdo, $personId['tarek'], [
        [$productId['Canned Chickpeas'], $bizId['cornerpantry'], 5, 5.00],
        [$productId['Day-Old Bagels'], $bizId['sunrisebakery'], 1, 2.00], // stock 1 -> 0, becomes "sold"
    ]);

    // Deliberately left pending - lets whoever seeds this data immediately try
    // out the "confirm sale" / "cancel sale" buttons in My Sales without
    // needing to place a fresh order first.
    seed_order($pdo, $personId['layla'], [
        [$productId['Farm Eggs (dozen)'], $bizId['dairyfresh'], 1, 2.50],
        [$productId['Organic Tomatoes'], $bizId['greengrocer'], 2, 1.50],
    ], autoFulfill: false);

    // ---------- 9. Reports ----------
    $insertReport = $pdo->prepare('INSERT INTO reports (reported_by, product_id, reported_user_id, reason, status) VALUES (?, ?, ?, ?, ?)');
    $insertReport->execute([$personId['nadine'], $productId['Overripe Bananas'], null, 'Looks moldy in the photo, please double check.', 'open']);
    $insertReport->execute([$personId['karim'], null, $bizId['sunrisebakery'], 'Never responded about pickup time.', 'resolved']);

    $pdo->commit();
} catch (Throwable $e) {
    $pdo->rollBack();
    send_error('Seeding failed - no changes were made.', 500, APP_ENV === 'local' ? [$e->getMessage()] : []);
}

send_json(true, 'Demo data seeded.', [
    'summary' => [
        'businesses' => count($businesses),
        'personal_users' => count($personals),
        'products' => count($products),
        'orders' => 3,
        'reports' => 2,
        'demo_password' => DEMO_PASSWORD,
        'demo_email_domain' => DEMO_DOMAIN,
    ],
]);
