<?php

class Customer extends Model
{
    protected string $table = 'customers';

    public function findByPhone(string $phone): array|false
    {
        $stmt = $this->db->prepare("SELECT * FROM customers WHERE phone = :phone LIMIT 1");
        $stmt->execute(['phone' => $phone]);
        return $stmt->fetch();
    }

    // Find existing customer by phone, or create a new one — used during order taking
    public function findOrCreate(string $phone, string $name, ?string $address = null): int
    {
        $existing = $this->findByPhone($phone);
        if ($existing) {
            if ($address && empty($existing['address'])) {
                $this->update($existing['id'], ['address' => $address]);
            }
            return (int) $existing['id'];
        }
        return $this->insert([
            'full_name' => $name ?: 'Walk-in Customer',
            'phone'     => $phone,
            'address'   => $address,
        ]);
    }

    // --- Customer app authentication (login/register/password reset) ---

    public function register(string $name, string $phone, string $password, ?string $email = null): array
    {
        $existing = $this->findByPhone($phone);
        if ($existing && !empty($existing['password_hash'])) {
            return ['success' => false, 'message' => 'An account with this phone number already exists. Please log in instead.'];
        }

        $hash = password_hash($password, PASSWORD_DEFAULT);

        if ($existing) {
            // A guest order created this phone number before — attach a password to it now
            $this->update($existing['id'], [
                'full_name'     => $name ?: $existing['full_name'],
                'email'         => $email,
                'password_hash' => $hash,
            ]);
            return ['success' => true, 'customer_id' => (int) $existing['id']];
        }

        $id = $this->insert([
            'full_name'     => $name,
            'phone'         => $phone,
            'email'         => $email,
            'password_hash' => $hash,
        ]);
        return ['success' => true, 'customer_id' => $id];
    }

    public function verifyLogin(string $phone, string $password): array|false
    {
        $customer = $this->findByPhone($phone);
        if (!$customer || empty($customer['password_hash'])) {
            return false;
        }
        if (!password_verify($password, $customer['password_hash'])) {
            return false;
        }
        return $customer;
    }

    public function createResetToken(string $phone): ?string
    {
        $customer = $this->findByPhone($phone);
        if (!$customer || empty($customer['password_hash'])) {
            return null; // don't reveal whether the phone exists — caller shows a generic message either way
        }
        $token = bin2hex(random_bytes(20));
        $this->update($customer['id'], [
            'reset_token'         => $token,
            'reset_token_expires' => date('Y-m-d H:i:s', strtotime('+30 minutes')),
        ]);
        return $token;
    }

    public function resetPasswordWithToken(string $token, string $newPassword): bool
    {
        $stmt = $this->db->prepare(
            "SELECT id FROM customers WHERE reset_token = :token AND reset_token_expires > NOW() LIMIT 1"
        );
        $stmt->execute(['token' => $token]);
        $row = $stmt->fetch();
        if (!$row) {
            return false;
        }
        $this->update((int) $row['id'], [
            'password_hash'       => password_hash($newPassword, PASSWORD_DEFAULT),
            'reset_token'         => null,
            'reset_token_expires' => null,
        ]);
        return true;
    }

    public function changePassword(int $customerId, string $currentPassword, string $newPassword): array
    {
        $customer = $this->find($customerId);
        if (!$customer || empty($customer['password_hash'])) {
            return ['success' => false, 'message' => 'Account not found.'];
        }
        if (!password_verify($currentPassword, $customer['password_hash'])) {
            return ['success' => false, 'message' => 'Your current password is incorrect.'];
        }
        $this->update($customerId, ['password_hash' => password_hash($newPassword, PASSWORD_DEFAULT)]);
        return ['success' => true];
    }

    public function updateProfile(int $customerId, string $name, ?string $email, ?string $address, ?string $dateOfBirth = null): array
    {
        if ($name === '') {
            return ['success' => false, 'message' => 'Name cannot be empty.'];
        }
        $this->update($customerId, [
            'full_name'     => $name,
            'email'         => $email,
            'address'       => $address,
            'date_of_birth' => $dateOfBirth ?: null,
        ]);
        return ['success' => true];
    }

    public function updateProfilePic(int $customerId, string $relativePath): void
    {
        // Remove the old picture file if one exists, to avoid orphaned uploads piling up
        $existing = $this->find($customerId);
        if ($existing && !empty($existing['profile_pic_path'])) {
            $oldPath = ROOT_PATH . '/public/' . $existing['profile_pic_path'];
            if (is_file($oldPath)) {
                @unlink($oldPath);
            }
        }
        $this->update($customerId, ['profile_pic_path' => $relativePath]);
    }

    public function getStats(int $customerId): array
    {
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) as order_count, COALESCE(SUM(CASE WHEN status != 'CANCELLED' THEN total_amount ELSE 0 END),0) as total_spent
             FROM orders WHERE customer_id = :id"
        );
        $stmt->execute(['id' => $customerId]);
        return $stmt->fetch();
    }

    public function touchLastActive(int $customerId): void
    {
        $this->update($customerId, ['last_active_at' => date('Y-m-d H:i:s')]);
    }

    public function onlineCount(int $minutes = 5): int
    {
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) as cnt FROM customers WHERE last_active_at >= DATE_SUB(NOW(), INTERVAL :mins MINUTE)"
        );
        $stmt->execute(['mins' => $minutes]);
        return (int) $stmt->fetch()['cnt'];
    }

    // Customers who have created an app account (password set) — i.e. "registered" rather than guest/walk-in
    public function registeredAppCustomers(): array
    {
        return $this->db->query(
            "SELECT c.*,
                    (SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.id) as order_count,
                    COALESCE((SELECT SUM(o.total_amount) FROM orders o WHERE o.customer_id = c.id AND o.status != 'CANCELLED'),0) as total_spent,
                    (SELECT MAX(o.created_at) FROM orders o WHERE o.customer_id = c.id) as last_order_at
             FROM customers c
             WHERE c.password_hash IS NOT NULL
             ORDER BY c.id DESC"
        )->fetchAll();
    }
}