<?php

declare(strict_types=1);

namespace App\Framework\Database\QueryBuilder\Examples;

use App\Framework\Database\EntityManager;

/**
 * Comprehensive QueryBuilder usage examples
 *
 * This class demonstrates various ways to use the QueryBuilder
 * with the EntityManager for type-safe database queries.
 */
final class QueryBuilderUsageExample
{
    public function __construct(
        private readonly EntityManager $entityManager
    ) {
    }

    /**
     * Basic SELECT queries
     */
    public function basicQueries(): void
    {
        // Simple select all from table
        $users = $this->entityManager
            ->createQueryBuilderForTable('users')
            ->execute();

        // Select specific columns
        $usernames = $this->entityManager
            ->createQueryBuilder()
            ->select('username', 'email')
            ->from('users')
            ->execute();

        // Select with alias
        $data = $this->entityManager
            ->createQueryBuilder()
            ->selectAs('username', 'user_name')
            ->selectAs('email', 'user_email')
            ->from('users')
            ->execute();
    }

    /**
     * WHERE clause examples
     */
    public function whereClauseExamples(): void
    {
        // Simple WHERE with equals
        $activeUsers = $this->entityManager
            ->createQueryBuilder()
            ->select('*')
            ->from('users')
            ->where('status', 'active')
            ->execute();

        // WHERE with different operators
        $recentUsers = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->whereOperator('created_at', '>=', '2024-01-01')
            ->whereOperator('age', '>', 18)
            ->execute();

        // WHERE IN clause
        $selectedUsers = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->whereIn('id', [1, 2, 3, 4, 5])
            ->execute();

        // WHERE BETWEEN
        $ageRangeUsers = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->whereBetween('age', 18, 65)
            ->execute();

        // WHERE LIKE for search
        $searchResults = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->whereLike('username', '%john%')
            ->execute();

        // NULL checks
        $usersWithoutEmail = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->whereNull('email')
            ->execute();

        $usersWithEmail = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->whereNotNull('email')
            ->execute();
    }

    /**
     * JOIN examples
     */
    public function joinExamples(): void
    {
        // INNER JOIN
        $usersWithPosts = $this->entityManager
            ->createQueryBuilder()
            ->select('u.username', 'p.title')
            ->from('users', 'u')
            ->join('posts', 'u.id = p.user_id', 'p')
            ->execute();

        // LEFT JOIN with WHERE
        $allUsersWithPostCount = $this->entityManager
            ->createQueryBuilder()
            ->select('u.username')
            ->selectCount('p.id', 'post_count')
            ->from('users', 'u')
            ->leftJoin('posts', 'u.id = p.user_id', 'p')
            ->groupBy('u.id', 'u.username')
            ->execute();

        // Multiple JOINs
        $detailedUserData = $this->entityManager
            ->createQueryBuilder()
            ->select('u.username', 'p.name as profile_name', 'c.name as company_name')
            ->from('users', 'u')
            ->leftJoin('user_profiles', 'u.id = p.user_id', 'p')
            ->leftJoin('companies', 'u.company_id = c.id', 'c')
            ->execute();
    }

    /**
     * Aggregate function examples
     */
    public function aggregateExamples(): void
    {
        // Count all users
        $totalUsers = $this->entityManager
            ->createQueryBuilder()
            ->selectCount('*', 'total')
            ->from('users')
            ->scalar();

        // Sum of all order amounts
        $totalSales = $this->entityManager
            ->createQueryBuilder()
            ->selectSum('amount', 'total_sales')
            ->from('orders')
            ->scalar();

        // Average age by group
        $avgAgeByDepartment = $this->entityManager
            ->createQueryBuilder()
            ->select('department')
            ->selectAvg('age', 'avg_age')
            ->from('employees')
            ->groupBy('department')
            ->execute();

        // Max and Min values
        $salaryRange = $this->entityManager
            ->createQueryBuilder()
            ->selectMin('salary', 'min_salary')
            ->selectMax('salary', 'max_salary')
            ->from('employees')
            ->first();
    }

    /**
     * Sorting and pagination examples
     */
    public function sortingAndPagination(): void
    {
        // Simple ordering
        $usersByName = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->orderByAsc('username')
            ->execute();

        // Multiple order criteria
        $sortedUsers = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->orderBy('status', 'DESC')
            ->orderBy('created_at', 'DESC')
            ->execute();

        // Pagination
        $page2Users = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->orderByAsc('username')
            ->paginate(2, 10) // Page 2, 10 per page
            ->execute();

        // Manual limit and offset
        $limitedUsers = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->limit(5)
            ->offset(10)
            ->execute();
    }

    /**
     * Entity hydration examples
     */
    public function entityHydrationExamples(): void
    {
        // Get entities instead of raw data (requires entity class)
        $userEntities = $this->entityManager
            ->createQueryBuilderFor('App\\Domain\\User\\User')
            ->where('status', 'active')
            ->getEntities();

        // First entity result
        $firstActiveUser = $this->entityManager
            ->createQueryBuilderFor('App\\Domain\\User\\User')
            ->where('status', 'active')
            ->orderByDesc('created_at')
            ->firstEntity();

        // Check if entities exist
        $hasActiveUsers = $this->entityManager
            ->createQueryBuilderFor('App\\Domain\\User\\User')
            ->where('status', 'active')
            ->exists();
    }

    /**
     * Subquery examples
     */
    public function subqueryExamples(): void
    {
        // Subquery in WHERE clause
        $topUsersSubquery = $this->entityManager
            ->createQueryBuilder()
            ->selectCount('*')
            ->from('posts')
            ->whereRaw('user_id = users.id');

        $activePosters = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->whereSubquery('id', 'IN', $topUsersSubquery)
            ->execute();
    }

    /**
     * Raw SQL examples for complex cases
     */
    public function rawSqlExamples(): void
    {
        // Raw SELECT expression
        $complexCalculation = $this->entityManager
            ->createQueryBuilder()
            ->selectRaw('(salary + bonus) * 0.8 as net_income')
            ->select('employee_name')
            ->from('employees')
            ->execute();

        // Raw WHERE condition
        $complexFilter = $this->entityManager
            ->createQueryBuilder()
            ->from('orders')
            ->whereRaw('YEAR(created_at) = ?', [2024])
            ->whereRaw('MONTH(created_at) BETWEEN ? AND ?', [1, 6])
            ->execute();
    }

    /**
     * Performance optimization examples
     */
    public function performanceExamples(): void
    {
        // Count without loading all data
        $totalActiveUsers = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->where('status', 'active')
            ->count();

        // Check existence without data loading
        $hasUsers = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->exists();

        // Efficient pagination with total count
        $queryBuilder = $this->entityManager
            ->createQueryBuilder()
            ->from('users')
            ->where('status', 'active')
            ->orderByAsc('username');

        $totalCount = $queryBuilder->count();
        $users = (clone $queryBuilder)->paginate(1, 10)->execute();
    }

    /**
     * Complex real-world example: User dashboard statistics
     */
    public function userDashboardStats(int $userId): array
    {
        // Total posts by user
        $totalPosts = $this->entityManager
            ->createQueryBuilder()
            ->from('posts')
            ->where('user_id', $userId)
            ->where('status', 'published')
            ->count();

        // Recent posts with engagement
        $recentPosts = $this->entityManager
            ->createQueryBuilder()
            ->select('p.title', 'p.created_at')
            ->selectCount('c.id', 'comment_count')
            ->selectSum('l.id', 'like_count')
            ->from('posts', 'p')
            ->leftJoin('comments', 'p.id = c.post_id', 'c')
            ->leftJoin('likes', 'p.id = l.post_id', 'l')
            ->where('p.user_id', $userId)
            ->where('p.status', 'published')
            ->groupBy('p.id', 'p.title', 'p.created_at')
            ->orderByDesc('p.created_at')
            ->limit(5)
            ->execute();

        // Monthly post statistics
        $monthlyStats = $this->entityManager
            ->createQueryBuilder()
            ->selectRaw('YEAR(created_at) as year')
            ->selectRaw('MONTH(created_at) as month')
            ->selectCount('*', 'post_count')
            ->from('posts')
            ->where('user_id', $userId)
            ->where('status', 'published')
            ->whereOperator('created_at', '>=', date('Y-m-d', strtotime('-12 months')))
            ->groupBy('year', 'month')
            ->orderBy('year', 'DESC')
            ->orderBy('month', 'DESC')
            ->execute();

        return [
            'total_posts' => $totalPosts,
            'recent_posts' => $recentPosts,
            'monthly_stats' => $monthlyStats,
        ];
    }

    /**
     * Advanced reporting example: Sales analytics
     */
    public function salesAnalytics(string $startDate, string $endDate): array
    {
        // Daily sales summary
        $dailySales = $this->entityManager
            ->createQueryBuilder()
            ->selectRaw('DATE(created_at) as sale_date')
            ->selectCount('*', 'order_count')
            ->selectSum('amount', 'total_amount')
            ->selectAvg('amount', 'avg_order_value')
            ->from('orders')
            ->where('status', 'completed')
            ->whereBetween('created_at', $startDate, $endDate)
            ->groupBy('sale_date')
            ->orderByDesc('sale_date')
            ->execute();

        // Top products
        $topProducts = $this->entityManager
            ->createQueryBuilder()
            ->select('p.name', 'p.price')
            ->selectSum('oi.quantity', 'total_sold')
            ->selectSum('oi.quantity * oi.price', 'total_revenue')
            ->from('order_items', 'oi')
            ->join('products', 'oi.product_id = p.id', 'p')
            ->join('orders', 'oi.order_id = o.id', 'o')
            ->where('o.status', 'completed')
            ->whereBetween('o.created_at', $startDate, $endDate)
            ->groupBy('p.id', 'p.name', 'p.price')
            ->orderByDesc('total_revenue')
            ->limit(10)
            ->execute();

        // Customer segments
        $customerSegments = $this->entityManager
            ->createQueryBuilder()
            ->selectRaw('
                CASE 
                    WHEN total_spent > 1000 THEN "Premium"
                    WHEN total_spent > 500 THEN "Standard"
                    ELSE "Basic"
                END as segment
            ')
            ->selectCount('*', 'customer_count')
            ->selectAvg('total_spent', 'avg_spent')
            ->from('(
                SELECT user_id, SUM(amount) as total_spent
                FROM orders 
                WHERE status = "completed" 
                AND created_at BETWEEN ? AND ?
                GROUP BY user_id
            ) as customer_totals')
            ->groupBy('segment')
            ->orderByDesc('avg_spent')
            ->execute();

        return [
            'daily_sales' => $dailySales,
            'top_products' => $topProducts,
            'customer_segments' => $customerSegments,
        ];
    }
}
