<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\Ticket;
use App\Models\Event;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
use App\Models\User;  // Correct namespace
use Illuminate\Support\Str;

class AuthenticatedSessionController extends Controller
{
    /**
     * Display the login view.
     */
    public function create(): View
    {
        return view('auth.login');
    }

    /**
     * Handle an incoming authentication request.
     */
    public function store(LoginRequest $request): RedirectResponse
    {
        $request->authenticate();

        $request->session()->regenerate();

        return redirect()->intended(route('dashboard', absolute: false));
    }

    /**
     * Destroy an authenticated session.
     */
    public function destroy(Request $request): RedirectResponse
    {
        Auth::guard('web')->logout();

        $request->session()->invalidate();

        $request->session()->regenerateToken();

        return redirect('/');
    }

    /**
     * Display the dashboard with ticket information.
     */
    /**
     * Display the dashboard with ticket information.
     */
    public function dashboard(Request $request): View
    {
        $search = $request->get('search');
        $status = $request->get('status');
        $event = $request->get('event');
        $school = $request->get('school');
        $stkStatus = $request->get('stk_status');
        $perPage = $request->get('per_page', 50);

        $user = Auth::user();

        $query = Ticket::with('event')
            ->leftJoin(DB::raw('(SELECT ticket_reference_number, stk_status FROM txn_logs WHERE id IN (SELECT MAX(id) FROM txn_logs GROUP BY ticket_reference_number)) as latest_txn'), 'tickets.reference', '=', 'latest_txn.ticket_reference_number')
            ->select('tickets.*', 'latest_txn.stk_status');

        // Search functionality
        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('tickets.first_name', 'like', "%{$search}%")
                    ->orWhere('tickets.last_name', 'like', "%{$search}%")
                    ->orWhere('tickets.phone', 'like', "%{$search}%")
                    ->orWhere('tickets.email', 'like', "%{$search}%")
                    ->orWhere('tickets.school', 'like', "%{$search}%")
                    ->orWhere('tickets.reference', 'like', "%{$search}%");
            });
        }

        // Status filter
        if ($status) {
            $query->where('tickets.payment_status', $status);
        }

        // Event filter
        if ($event) {
            $query->where('tickets.event_id', $event);
        }

        // School filter
        if ($school) {
            $query->where('tickets.school', $school);
        }

        // STK Status filter
        if ($stkStatus) {
            $query->where('latest_txn.stk_status', $stkStatus);
        }

        // Order by payment_date (purchase date) descending, then fallback to created_at
        $tickets = $query->orderByDesc('tickets.id')
            ->orderByDesc('tickets.created_at')
            ->paginate($perPage)
            ->withQueryString();

        // Get all events for filter dropdown
        $events = Event::orderBy('name')->get();

        // Get all schools for filter dropdown
        $schools = Ticket::distinct()
            ->whereNotNull('school')
            ->pluck('school')
            ->sort()
            ->values();

        // Calculate today's metrics
        $todaySales = Ticket::where('payment_status', 'completed')->whereDate('payment_date', today())->count();
        $todayRevenue = Ticket::where('payment_status', 'completed')->whereDate('payment_date', today())->sum('total_amount');
        $totalRevenue = Ticket::where('payment_status', 'completed')->sum('total_amount');

        // Calculate yesterday's metrics for comparison
        $yesterday = Carbon::yesterday();
        $yesterdaySales = Ticket::where('payment_status', 'completed')->whereDate('payment_date', $yesterday)->count();
        $yesterdayRevenue = Ticket::where('payment_status', 'completed')->whereDate('payment_date', $yesterday)->sum('total_amount');

        // Week-over-week comparison for total revenue
        $lastWeekStart = Carbon::today()->subWeeks(2)->startOfDay();
        $lastWeekEnd = Carbon::today()->subWeek()->endOfDay();
        $lastWeekRevenue = Ticket::where('payment_status', 'completed')
            ->whereBetween('payment_date', [$lastWeekStart, $lastWeekEnd])
            ->sum('total_amount');

        $thisWeekStart = Carbon::today()->subWeek()->startOfDay();
        $thisWeekEnd = Carbon::today()->endOfDay();
        $thisWeekRevenue = Ticket::where('payment_status', 'completed')
            ->whereBetween('payment_date', [$thisWeekStart, $thisWeekEnd])
            ->sum('total_amount');

        // Helper function to calculate percentage change
        $calculateChange = function ($current, $previous) {
            if ($previous == 0) {
                return $current > 0 ? '+100' : '0';
            }
            $change = (($current - $previous) / $previous) * 100;
            $formatted = number_format(abs($change), 0);
            return $change > 0 ? "+{$formatted}" : ($change < 0 ? "-{$formatted}" : "0");
        };

        // Helper function to determine direction
        $getDirection = function ($current, $previous) {
            if ($previous == 0) {
                return $current > 0 ? 'positive' : 'neutral';
            }
            $change = $current - $previous;
            return $change > 0 ? 'positive' : ($change < 0 ? 'negative' : 'neutral');
        };

        // Get ticket stats - apply role-based filtering
        $ticketStats = [
            'total_tickets' => Ticket::count(),
            'total_paid' => Ticket::where('payment_status', 'completed')->count(),
            'total_pending' => Ticket::where('payment_status', 'pending')->count(),
            'total_failed' => Ticket::where('payment_status', 'failed')->count(),
            'today_sales' => $todaySales,
            'this_month_sales' => Ticket::where('payment_status', 'completed')
                ->whereMonth('payment_date', now()->month)
                ->whereYear('payment_date', now()->year)->count(),

            // Yesterday's data
            'yesterday_sales' => $yesterdaySales,
            'yesterday_revenue' => $yesterdayRevenue,

            // Percentage changes
            'total_revenue_change' => $calculateChange($thisWeekRevenue, $lastWeekRevenue) . '%',
            'today_sales_change' => $calculateChange($todaySales, $yesterdaySales) . '%',
            'today_revenue_change' => $calculateChange($todayRevenue, $yesterdayRevenue) . '%',

            // Change directions
            'total_revenue_direction' => $getDirection($thisWeekRevenue, $lastWeekRevenue),
            'today_sales_direction' => $getDirection($todaySales, $yesterdaySales),
            'today_revenue_direction' => $getDirection($todayRevenue, $yesterdayRevenue),
        ];

        // Determine whether the current User model supports roles/permissions (Spatie HasRoles trait)
        $canViewMetrics = false;
        $isCustomerSupport = false;
        $isManagement = false;

        if ($user) {
            $uses = class_uses(get_class($user)) ?: [];
            if (in_array(\Spatie\Permission\Traits\HasRoles::class, $uses, true)) {
                // Safe to call role/permission methods
                try {
                    $hasPermissionTo = is_callable([$user, 'hasPermissionTo']) ? call_user_func([$user, 'hasPermissionTo'], 'view-metrics') : false;
                    $hasAnyRole = is_callable([$user, 'hasAnyRole']) ? call_user_func([$user, 'hasAnyRole'], ['super-admin', 'management']) : false;

                    $canViewMetrics = $hasPermissionTo || $hasAnyRole;

                    $isCustomerSupport = is_callable([$user, 'hasRole']) ? call_user_func([$user, 'hasRole'], 'customer-support') : false;
                    $isManagement = is_callable([$user, 'hasRole']) ? call_user_func([$user, 'hasRole'], 'management') : false;
                } catch (\Throwable $e) {
                    // In case something unexpected happens, default to no special permissions
                    Log::warning('Role/permission check failed: ' . $e->getMessage());
                    $canViewMetrics = false;
                    $isCustomerSupport = false;
                    $isManagement = false;
                }
            }
        }

        // Add revenue metrics only for users with appropriate permissions or roles
        if ($canViewMetrics) {
            $ticketStats['total_revenue'] = $totalRevenue;
            $ticketStats['today_revenue'] = $todayRevenue;
            $ticketStats['this_month_revenue'] = Ticket::where('payment_status', 'completed')
                ->whereMonth('payment_date', now()->month)
                ->whereYear('payment_date', now()->year)->sum('total_amount');
        }

        // Role-specific adjustments
        if ($isCustomerSupport) {
            // Customer support sees basic ticket info but no revenue metrics
            // The revenue metrics are already excluded above due to permission check
        }

        if ($isManagement) {
            // Management sees all metrics (they have view-metrics permission)
            // No need to adjust as they'll get all stats
        }

        return view('dashboard-v2', compact('tickets', 'events', 'schools', 'ticketStats', 'search', 'status', 'event', 'school', 'stkStatus', 'perPage'));
    }

    public function export(Request $request)
    {
        $status = $request->get('status');
        $event = $request->get('event');
        $school = $request->get('school');
        $stkStatus = $request->get('stk_status');

        $query = Ticket::with('event')
            ->leftJoin(DB::raw('(SELECT ticket_reference_number, stk_status FROM txn_logs WHERE id IN (SELECT MAX(id) FROM txn_logs GROUP BY ticket_reference_number)) as latest_txn'), 'tickets.reference', '=', 'latest_txn.ticket_reference_number')
            ->select('tickets.*', 'latest_txn.stk_status');

        if ($status) {
            $query->where('tickets.payment_status', $status);
        }

        if ($event) {
            $query->where('tickets.event_id', $event);
        }

        if ($school) {
            $query->where('tickets.school', $school);
        }

        if ($stkStatus) {
            $query->where('latest_txn.stk_status', $stkStatus);
        }

        $tickets = $query->orderBy('tickets.created_at', 'desc')->get();

        $filename = 'tickets_export_' . date('Y-m-d_H-i-s') . '.csv';

        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => "attachment; filename=\"{$filename}\"",
        ];

        $callback = function () use ($tickets) {
            $file = fopen('php://output', 'w');

            // CSV headers
            fputcsv($file, [
                'ID',
                'Reference',
                'Event',
                'First Name',
                'Last Name',
                'Phone',
                'Email',
                'School',
                'Quantity',
                'Amount',
                'Total Amount',
                'Payment Status',
                'STK Status',
                'M-Pesa Receipt',
                'Payment Date',
                'Created At'
            ]);

            foreach ($tickets as $ticket) {
                fputcsv($file, [
                    $ticket->id,
                    $ticket->reference,
                    $ticket->event ? $ticket->event->name : 'N/A',
                    $ticket->first_name,
                    $ticket->last_name,
                    $ticket->phone,
                    $ticket->email,
                    $ticket->school,
                    $ticket->quantity,
                    $ticket->amount,
                    $ticket->total_amount,
                    $ticket->payment_status,
                    $ticket->stk_status ?: 'N/A',
                    $ticket->mpesa_receipt_number,
                    $ticket->payment_date ? (is_string($ticket->payment_date) ? $ticket->payment_date : $ticket->payment_date->format('Y-m-d H:i:s')) : '',
                    $ticket->created_at ? $ticket->created_at->format('Y-m-d H:i:s') : '',
                ]);
            }

            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    public function analytics()
    {
        // Get daily sales for the last 30 days
        $dailySales = Ticket::where('payment_status', 'completed')
            ->where('payment_date', '>=', now()->subDays(30))
            ->selectRaw('DATE(payment_date) as date, COUNT(*) as count, SUM(total_amount) as revenue')
            ->groupBy('date')
            ->orderBy('date')
            ->get();

        // Get sales by school
        $schoolSales = Ticket::where('payment_status', 'completed')
            ->selectRaw('school, COUNT(*) as count, SUM(total_amount) as revenue')
            ->groupBy('school')
            ->orderByDesc('revenue')
            ->limit(10)
            ->get();

        // Get sales by event
        $eventSales = Ticket::where('payment_status', 'completed')
            ->join('events', 'tickets.event_id', '=', 'events.id')
            ->selectRaw('events.name as event_name, COUNT(*) as count, SUM(tickets.total_amount) as revenue')
            ->groupBy('events.id')
            ->orderByDesc('revenue')
            ->get();

        // Get payment status distribution
        $statusDistribution = Ticket::selectRaw('payment_status, COUNT(*) as count')
            ->groupBy('payment_status')
            ->get();

        return view('dashboard.analytics', compact('dailySales', 'schoolSales', 'eventSales', 'statusDistribution'));
    }

    // Handles POST /login/otp/generate
    // Handles POST /login/otp/generate
    public function otp(Request $request)
    {
        $request->validate([
            'phone' => 'required|string'
        ]);

        $cleanedPhone = $this->cleanPhoneNumber($request->phone);

        if (!$cleanedPhone) {
            return response()->json([
                'error' => 'Invalid phone number format. Please use format like 0712345678'
            ], 400);
        }

        $lastNineDigits = substr($cleanedPhone, -9);
        $user = User::where('phone', 'LIKE', '%' . $lastNineDigits)->first();

        if (!$user) {
            return response()->json([
                'error' => 'Unauthorized access. Phone number not registered.'
            ], 401);
        }

        $otp = rand(100000, 999999);
        $user->otp = $otp;
        $user->otp_expires_at = now()->addMinutes(5);
        $user->save();

        $message = "Your OTP is $otp. Do not share this with anyone.";
        $response = $this->sendSmsViaWasiliana($cleanedPhone, $message);

        if ($response['success']) {
            return response()->json([
                'message' => 'OTP sent successfully',
                'phone' => $cleanedPhone
            ]);
        }

        return response()->json([
            'error' => 'Failed to send OTP',
            'details' => $response['error_data'] ?? null
        ], 500);
    }

    // Handles POST /login/otp
    public function loginWithOtp(Request $request)
    {
        $request->validate([
            'phone' => 'required|string',
            'otp' => 'required|string|digits:6'
        ]);

        $cleanedPhone = $this->cleanPhoneNumber($request->phone);
        $lastNineDigits = substr($cleanedPhone, -9);
        $user = User::where('phone', 'LIKE', '%' . $lastNineDigits)->first();

        if (!$user) {
            return back()->withErrors([
                'phone' => 'Unauthorized access. Phone number not registered.'
            ]);
        }

        if (!$user->verifyOtp($request->otp)) {
            return back()->withErrors([
                'otp' => 'Invalid or expired OTP code'
            ]);
        }

        Auth::login($user);
        return redirect()->intended(route('dashboard'));
    }
    private function sendSmsViaWasiliana($phoneNumber, $message)
    {
        try {
            // Clean phone number (ensure it starts with 254)
            $cleanedPhone = $this->cleanPhoneNumber($phoneNumber);

            if (!$cleanedPhone) {
                return [
                    'success' => false,
                    'error_data' => ['error' => 'Invalid phone number format']
                ];
            }

            // Use the same working configuration from Homecontroller
            $client = new Client();

            $headers = [
                'Content-Type' => 'application/json',
                'ApiKey' => '2ZqSn5LGPfNyTpvRICWiG3vWnJim6zTR6oXimzg29Isn3niqSrXO8fKrOv4FZDSa',
            ];

            $body = [
                'from' => 'PACESETTER',
                'recipients' => [$cleanedPhone],
                'message' => $message,
            ];

            $response = $client->post('https://api.wasiliana.com/api/v1/send/sms', [
                'headers' => $headers,
                'json' => $body,
                'verify' => false // This disables SSL certificate verification
            ]);

            $responseData = json_decode($response->getBody(), true);

            Log::info('SMS sent successfully via Wasiliana', [
                'recipient' => $cleanedPhone,
                'response' => $responseData
            ]);

            // Check if the response indicates success
            if ($response->getStatusCode() === 200) {
                return [
                    'success' => true,
                    'message_id' => $responseData['messageId'] ?? $responseData['id'] ?? null,
                    'cost' => $responseData['cost'] ?? 1.00, // Default cost if not provided
                ];
            } else {
                Log::error('Wasiliana API Error: ' . $response->getBody());
                return [
                    'success' => false,
                    'error_data' => [
                        'status' => $response->getStatusCode(),
                        'response' => $responseData
                    ]
                ];
            }
        } catch (\Exception $e) {
            Log::error('SMS sending error: ' . $e->getMessage());
            return [
                'success' => false,
                'error_data' => ['error' => $e->getMessage()]
            ];
        }
    }
    private function cleanPhoneNumber($phone)
    {
        // Remove all non-digit characters
        $cleaned = preg_replace('/[^0-9]/', '', $phone);

        // Convert to 254 format if in local format
        if (strlen($cleaned) === 10 && str_starts_with($cleaned, '0')) {
            return '254' . substr($cleaned, 1);
        }

        // Return as-is if already in 254 format
        if (strlen($cleaned) === 12 && str_starts_with($cleaned, '254')) {
            return $cleaned;
        }

        return null; // Invalid format
    }
}
