<?php

namespace App\Http\Controllers;

use App\Models\Bill;
use App\Jobs\SendRentInvoiceEmail;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Mail\BillNotification;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;


class BillEmailController extends Controller
{
    public function sendAllBills(Request $request)
    {
        $request->validate([
            'billing_period' => 'required|string',
            'subject' => 'nullable|string|max:255',
            'message' => 'nullable|string',
            'include_pdf' => 'boolean'
        ]);

        $billingPeriod = $request->input('billing_period');
        $subject = $request->input('subject');
        $message = $request->input('message');
        $includePdf = $request->boolean('include_pdf', true);

        Log::info("SendAllBills method called", [
            'billing_period' => $billingPeriod,
            'subject' => $subject,
            'message' => $message,
            'include_pdf' => $includePdf
        ]);

        $companyId = session('CompanyID');

        // Convert YYYY-MM to YYYYMM format for database query if needed
        $dbBillingPeriod = str_replace('-', '', $billingPeriod);
        
        // Get all bills for the selected billing period
        $bills = DB::table('rentservicebill')
            ->where('CompanyID', $companyId)
            ->where('BillingPeriod', $dbBillingPeriod)
            ->limit(50) // Limit to prevent timeout
            ->get();
            
        Log::info("Billing period query", ['input' => $billingPeriod, 'db_format' => $dbBillingPeriod, 'bill_count' => $bills->count()]);

        if ($bills->isEmpty()) {
            return redirect()->back()->with('error', 'No bills found for the selected billing period.');
        }

        // Check if there are more bills than the limit
        $totalBills = DB::table('rentservicebill')
            ->where('CompanyID', $companyId)
            ->where('BillingPeriod', $dbBillingPeriod)
            ->count();
            
        if ($totalBills > 50) {
            return redirect()->back()->with('warning', "Found {$totalBills} bills. Processing first 50 to prevent timeout. Please run multiple times for all bills.");
        }

        // Set time limit to prevent timeout
        set_time_limit(300); // 5 minutes
        
        // For testing: Process synchronously instead of dispatching to queue
        $successCount = 0;
        $errorCount = 0;
        
        // Get company information once to avoid repeated queries
        $company = DB::table('company')->where('CompanyID', $companyId)->first();
        
        // Preload all customer data to reduce database queries
        $customerIds = $bills->pluck('CustomerID')->unique();
        $customers = DB::table('customer')->whereIn('CustomerID', $customerIds)->get()->keyBy('CustomerID');
        
        // Preload all bill lines to reduce database queries
        $billIds = $bills->pluck('BillID');
        $billLines = DB::table('rentservicebillline')->whereIn('BillID', $billIds)->get()->groupBy('BillID');
        
        foreach ($bills as $bill) {
            try {
                // Use preloaded customer data
                $customer = $customers->get($bill->CustomerID);

                if (!$customer || !$customer->Email) {
                    Log::error("No email found for customer: {$bill->CustomerID} (Bill #{$bill->BillID})");
                    $errorCount++;
                    continue;
                }

                $bill->customer = $customer;
                
                // Use preloaded bill lines
                $bill->lines = $billLines->get($bill->BillID, collect());

                // Prepare template variables
                $variables = [
                    'customer_name' => $customer->CustomerName ?? 'Valued Customer',
                    'bill_id' => $bill->BillID,
                    'billing_period' => $bill->BillingPeriod,
                    'account_number' => $customer->AccountNo ?? 'N/A',
                    'total_amount' => 'KES ' . number_format($bill->TotalAmount, 2),
                    'company_name' => $company->CompanyName ?? config('app.name')
                ];

                // Use company's custom templates with variables replaced
                // For send all, always use company templates to ensure personalization
                $personalizedSubject = CompanySettingsController::getSubjectTemplate($companyId, $variables);
                $personalizedMessage = CompanySettingsController::getEmailTemplate($companyId, $variables);

                Log::info('Personalized templates prepared for bill #' . $bill->BillID, [
                    'variables' => $variables,
                    'subject' => $personalizedSubject,
                    'message_preview' => substr($personalizedMessage, 0, 200) . '...',
                    'used_custom_subject' => !empty($subject),
                    'used_custom_message' => !empty($message),
                    'customer_name_in_variables' => $variables['customer_name'],
                    'bill_id_in_variables' => $variables['bill_id']
                ]);

                // Generate PDF if needed
                $pdfPath = null;
                if ($includePdf) {
                    Log::info("Generating PDF for bill #{$bill->BillID}");
                    // Generate PDF (you'll need to implement this method)
                    $pdfPath = $this->generatePdf($bill);
                    if (!$pdfPath) {
                        Log::error("Failed to generate PDF for bill #{$bill->BillID}");
                        $errorCount++;
                        continue;
                    }
                }

                // Send email using BillNotification
                Log::info("Sending email for bill #{$bill->BillID} to {$customer->Email}");
                
                // Pass the already-personalized subject and message to BillNotification
                // Pass null for subject and message so BillNotification doesn't try to fetch templates again
                Mail::to($customer->Email)->send(new BillNotification($bill, $personalizedSubject, $personalizedMessage, $pdfPath));
                
                // Clean up PDF file if it was generated
                if ($pdfPath && file_exists($pdfPath)) {
                    unlink($pdfPath);
                }
                
                $successCount++;
                Log::info("Successfully sent email for bill #{$bill->BillID}");
                
                // Add small delay to prevent overwhelming the mail server
                usleep(100000); // 0.1 second delay
                
            } catch (\Exception $e) {
                Log::error("Failed to send email for bill #{$bill->BillID}: " . $e->getMessage(), [
                    'exception' => $e,
                    'bill_id' => $bill->BillID,
                    'customer_id' => $bill->CustomerID
                ]);
                $errorCount++;
                
                // Continue with next bill even if one fails
                continue;
            }
        }

        $message = "Processed {$bills->count()} invoices. Successfully sent: {$successCount}, Failed: {$errorCount}.";
        
        if ($errorCount > 0) {
            $message .= " Some emails failed to send. Please check logs for details.";
            return redirect()->back()->with('warning', $message);
        }
        
        return redirect()->back()->with('success', $message);
    }

    public function sendBill(Request $request, $billId)
    {
        \Log::info('SendBill method called', ['billId' => $billId, 'request_data' => $request->all()]);
        
        $request->validate([
            'email' => 'required|email',
            'subject' => 'nullable|string|max:255',
            'message' => 'nullable|string',
            'include_pdf' => 'boolean'
        ]);

        $companyId = $this->user()->CompanyID;
        
        if (!$companyId) {
            \Log::error('No company associated with user');
            return redirect()->back()->with('error', 'No company associated with this account.');
        }

        $bill = DB::table('rentservicebill')
                    ->where('BillID', $billId)
                    ->where('CompanyID', $companyId) // Add CompanyID filter
                    ->first();
                    
        if (!$bill) {
            \Log::error('Bill not found', ['billId' => $billId, 'companyId' => $companyId]);
            return redirect()->back()->with('error', 'Bill not found or you do not have permission to access it.');
        }
        
        // Load customer data
        $customer = DB::table('customer')->where('CustomerID', $bill->CustomerID)->first();
        $bill->customer = $customer;
        
        // Load bill lines from rentservicebillline table
        $bill->lines = DB::table('rentservicebillline')
                        ->where('BillID', $bill->BillID)
                        ->get();

        // Get company information
        $company = DB::table('company')->where('CompanyID', $companyId)->first();
        
        // Prepare template variables
        $variables = [
            'customer_name' => $customer->CustomerName ?? 'Valued Customer',
            'bill_id' => $bill->BillID,
            'billing_period' => $bill->BillingPeriod,
            'account_number' => $customer->AccountNo ?? 'N/A',
            'total_amount' => 'KES ' . number_format($bill->TotalAmount, 2),
            'company_name' => $company->CompanyName ?? config('app.name')
        ];

        \Log::info('Template variables prepared', ['variables' => $variables]);

        // Use company's custom templates or defaults
        // If user provided custom subject/message in form, use those, otherwise use company templates
        $subject = $request->input('subject');
        $message = $request->input('message');
        
        if (empty($subject)) {
            $subject = CompanySettingsController::getSubjectTemplate($companyId, $variables);
        }
        
        if (empty($message)) {
            $message = CompanySettingsController::getEmailTemplate($companyId, $variables);
        }
        $includePdf = $request->boolean('include_pdf', true);

        \Log::info('Attempting to send email', ['email' => $request->email, 'subject' => $subject, 'includePdf' => $includePdf]);

        try {
            // If include_pdf is true, generate and attach the PDF
            $pdfPath = null;
            if ($includePdf) {
                \Log::info('Generating PDF for bill');
                // Generate PDF (you'll need to implement this method)
                $pdfPath = $this->generatePdf($bill);
            }

            // Send email
            \Log::info('Sending email via Mail facade');
            Mail::to($request->email)->send(new BillNotification($bill, $subject, $message, $pdfPath));

            \Log::info('Email sent successfully');

            // Delete the temporary PDF file if it was created
            if ($pdfPath && file_exists($pdfPath)) {
                unlink($pdfPath);
            }

            return redirect()->back()->with('success', 'Bill sent successfully to ' . $request->email);
        } catch (\Exception $e) {
            \Log::error('Failed to send email', ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
            
            // Clean up the PDF file if it was created but there was an error
            if (isset($pdfPath) && file_exists($pdfPath)) {
                unlink($pdfPath);
            }
            
            return redirect()->back()->with('error', 'Failed to send email: ' . $e->getMessage());
        }
    }

    /**
     * Generate PDF for the bill
     * 
     * @param  \App\Models\Bill  $bill
     * @return string Path to the generated PDF
     */
    protected function generatePdf($bill)
    {
        // Generate a unique filename with the bill's BillID
        $filename = 'bill_' . $bill->BillID . '_' . now()->format('YmdHis') . '.pdf';
        $path = storage_path('app/temp/' . $filename);
        
        // Ensure the temp directory exists
        if (!file_exists(dirname($path))) {
            mkdir(dirname($path), 0755, true);
        }

        // Calculate total amount from bill lines
        $totalAmount = collect($bill->lines)->sum('LineAmount');

        // Generate PDF using the rentbill view with the required data
        $pdf = \Barryvdh\DomPDF\Facade\Pdf::loadView('pdf.rentbill', [
            'invoice' => $bill,
            'customer' => $bill->customer,
            'totalAmount' => $totalAmount
        ]);

        // Save the PDF to a temporary file
        $pdf->save($path);

        return $path;
    }
}
