<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\Transaction;
use App\Models\Ticket;
use App\Models\TxnLog;
use App\Models\SmsLog;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use GuzzleHttp\Client;

class CsvProcessorController extends Controller
{
    public function index()
    {
        return view('csv-processor.index');
    }

    public function process(Request $request)
    {
        $request->validate([
            'csv_file' => 'required|file|mimes:csv,txt'
        ]);

        try {
            $file = $request->file('csv_file');
            $csvData = $this->parseCsv($file);

            $results = $this->processCsvData($csvData);

            return view('csv-processor.results', compact('results'));
        } catch (\Exception $e) {
            Log::error('CSV Processing Error: ' . $e->getMessage());
            return back()->with('error', 'Error processing CSV: ' . $e->getMessage());
        }
    }

    private function parseCsv($file)
    {
        $csvData = [];
        $handle = fopen($file->getPathname(), 'r');

        // Skip header row
        $header = fgetcsv($handle);

        while (($row = fgetcsv($handle)) !== false) {
            if (count($row) >= 13) { // Ensure we have all required columns
                $csvData[] = [
                    'receipt_no' => $row[0],
                    'completion_time' => $row[1],
                    'initiation_time' => $row[2],
                    'details' => $row[3],
                    'transaction_status' => $row[4],
                    'paid_in' => $row[5],
                    'withdrawn' => $row[6],
                    'balance' => $row[7],
                    'balance_confirmed' => $row[8],
                    'reason_type' => $row[9],
                    'other_party_info' => $row[10],
                    'linked_transaction_id' => $row[11],
                    'account_no' => $row[12], // This is the bill_ref_number we need
                    'currency' => $row[13] ?? 'KES'
                ];
            }
        }

        fclose($handle);
        return $csvData;
    }

    private function processCsvData($csvData)
    {
        $results = [
            'processed' => 0,
            'transactions_created' => 0,
            'transactions_existed' => 0,
            'tickets_updated' => 0,
            'sms_sent' => 0,
            'sms_failed' => 0,
            'skipped' => 0,
            'errors' => []
        ];

        DB::beginTransaction();

        try {
            foreach ($csvData as $row) {
                $results['processed']++;

                // Skip if transaction status is not completed
                if ($row['transaction_status'] !== 'Completed') {
                    $results['skipped']++;
                    continue;
                }

                // Extract bill reference number from account_no column
                $billRefNumber = trim($row['account_no']); // Remove leading/trailing spaces

                Log::info('Looking for ticket', [
                    'bill_ref_number' => $billRefNumber,
                    'length' => strlen($billRefNumber)
                ]);

                // Find ticket by reference number (with trimmed reference)
                $ticket = Ticket::where('reference', $billRefNumber)->first();

                // If not found, try with original (in case there are spaces in the database)
                if (!$ticket) {
                    $ticket = Ticket::where('reference', 'like', '%' . $billRefNumber . '%')->first();
                }

                if (!$ticket) {
                    $results['errors'][] = "Ticket not found for reference: {$billRefNumber}";
                    continue;
                }

                // Check if transaction already exists
                $existingTransaction = Transaction::where('trans_id', $row['receipt_no'])->first();
                $transactionCreated = false;

                if (!$existingTransaction) {
                    // Create transaction record
                    $transaction = Transaction::create([
                        'transaction_type' => 'pay_bill',
                        'trans_id' => $row['receipt_no'],
                        'trans_time' => $this->formatTransTime($row['completion_time']),
                        'trans_amount' => $this->parseAmount($row['paid_in']),
                        'business_short_code' => null,
                        'bill_ref_number' => $billRefNumber,
                        'invoice_number' => null,
                        'org_account_balance' => $this->parseAmount($row['balance']),
                        'third_party_trans_id' => $row['linked_transaction_id'],
                        'msisdn' => $this->extractPhoneNumber($row['other_party_info']),
                        'first_name' => $this->extractFirstName($row['other_party_info'])
                    ]);
                    $transactionCreated = true;
                    $results['transactions_created']++;
                } else {
                    $results['transactions_existed']++;
                    // Skip SMS since transaction already exists (user already received SMS)
                    Log::info('Transaction already exists, skipping SMS', [
                        'transaction_id' => $existingTransaction->trans_id,
                        'ticket_reference' => $ticket->reference
                    ]);
                    continue; // Skip the rest of the processing for this record
                }

                Log::info('Ticket found for SMS', [
                    'ticket_id' => $ticket->id,
                    'ticket_reference' => $ticket->reference,
                    'ticket_phone' => $ticket->phone,
                    'phone_length' => strlen($ticket->phone ?? ''),
                    'phone_empty' => empty($ticket->phone)
                ]);

                // Update ticket payment status (always update, even if transaction exists)
                $paymentDate = $this->parseDateTime($row['completion_time']);
                Log::info('Parsing payment date', [
                    'original' => $row['completion_time'],
                    'parsed' => $paymentDate,
                    'ticket_id' => $ticket->id
                ]);

                // Prepare update data
                $updateData = [
                    'payment_status' => 'completed',
                    'mpesa_receipt_number' => $row['receipt_no']
                ];

                // Only set payment_date if we have a valid date
                if ($paymentDate && $paymentDate instanceof \Carbon\Carbon) {
                    $updateData['payment_date'] = $paymentDate;
                } else {
                    // Set to current time if parsing failed
                    $updateData['payment_date'] = now();
                }

                $ticket->update($updateData);

                $results['tickets_updated']++;

                Log::info('Ticket updated and SMS processing', [
                    'ticket_id' => $ticket->id,
                    'ticket_reference' => $ticket->reference,
                    'transactions_created' => $results['transactions_created'],
                    'transactions_existed' => $results['transactions_existed'],
                    'tickets_updated' => $results['tickets_updated']
                ]);

                // Send SMS notification to user
                $smsResult = $this->sendTicketConfirmationSms($ticket);
                if ($smsResult['success']) {
                    $results['sms_sent']++;
                } else {
                    $results['sms_failed']++;
                    $results['errors'][] = "SMS failed for ticket {$ticket->reference}: " . $smsResult['error'];
                }
            }

            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();
            throw $e;
        }

        return $results;
    }

    private function formatTransTime($dateTime)
    {
        try {
            $date = \DateTime::createFromFormat('d-m-Y H:i:s', $dateTime);
            return $date ? $date->format('YmdHis') : date('YmdHis');
        } catch (\Exception $e) {
            return date('YmdHis');
        }
    }

    private function parseAmount($amount)
    {
        // Remove commas and convert to float
        return (float) str_replace(',', '', $amount);
    }

    private function parseDateTime($dateTime)
    {
        try {
            // Handle empty or null values
            if (empty($dateTime) || $dateTime === null) {
                return now();
            }

            // Handle the specific format from CSV: "23-10-2025 23:06:23"
            $date = \DateTime::createFromFormat('d-m-Y H:i:s', $dateTime);

            if ($date === false) {
                // Try alternative formats
                $date = \DateTime::createFromFormat('Y-m-d H:i:s', $dateTime);
                if ($date === false) {
                    $date = \DateTime::createFromFormat('d/m/Y H:i:s', $dateTime);
                }
                if ($date === false) {
                    $date = \DateTime::createFromFormat('Y-m-d H:i:s', $dateTime);
                }
            }

            if ($date === false) {
                Log::warning('Failed to parse datetime: ' . $dateTime);
                // Return current datetime as Carbon instance
                return now();
            }

            // Ensure we return a Carbon instance
            return \Carbon\Carbon::instance($date);
        } catch (\Exception $e) {
            Log::warning('Exception parsing datetime: ' . $dateTime, ['error' => $e->getMessage()]);
            return now();
        }
    }

    private function extractPhoneNumber($otherPartyInfo)
    {
        // Extract phone number from other party info
        preg_match('/\d{10,12}/', $otherPartyInfo, $matches);
        return $matches[0] ?? '';
    }

    private function extractFirstName($otherPartyInfo)
    {
        // Extract first name from other party info
        $parts = explode(' - ', $otherPartyInfo);
        if (count($parts) > 1) {
            $namePart = $parts[1];
            $nameParts = explode(' ', $namePart);
            return $nameParts[0] ?? '';
        }
        return '';
    }

    private function sendTicketConfirmationSms($ticket)
    {
        try {
            $phone = $this->cleanPhoneNumber($ticket->phone);

            if (!$phone) {
                return [
                    'success' => false,
                    'error' => 'Invalid phone number format: ' . ($ticket->phone ?? 'null')
                ];
            }

            // Create SMS message similar to the one used in Homecontroller
            $message = "Dear {$ticket->first_name} {$ticket->last_name}, Welcome to {$ticket->event->name}! Ticket #: {$ticket->reference} Tickets: {$ticket->quantity} Get your tickets here: " . url("/get/ticket/{$ticket->reference}");

            // Send SMS via Wasiliana API
            $result = $this->sendSmsViaWasiliana($phone, $message);

            if ($result['success']) {
                // Log SMS in database
                $this->logSms($ticket, $message, $result);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('SMS sending failed for ticket ' . $ticket->reference, [
                'error' => $e->getMessage(),
                'phone' => $ticket->phone
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    private function sendSmsViaWasiliana($phoneNumber, $message)
    {
        try {
            $client = new Client([
                'timeout' => 30,
                'verify' => false,
                'http_errors' => false
            ]);

            $response = $client->post('https://api.wasiliana.com/api/v1/send/sms', [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'ApiKey' => '2ZqSn5LGPfNyTpvRICWiG3vWnJim6zTR6oXimzg29Isn3niqSrXO8fKrOv4FZDSa',
                ],
                'json' => [
                    'from' => 'PACESETTER',
                    'recipients' => [$phoneNumber],
                    'message' => $message,
                    'type' => 'plain',
                    'dlr' => 'yes',
                    'unicode' => 'no',
                    'skipOtp' => true,
                    'messageClass' => 'normal'
                ]
            ]);

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

            if ($statusCode !== 200) {
                throw new \Exception($responseData['message'] ?? "API returned status code $statusCode");
            }

            if (($responseData['status'] ?? 'failed') !== 'success') {
                throw new \Exception('Invalid response from SMS gateway: ' . json_encode($responseData));
            }

            return [
                'success' => true,
                'message_id' => $responseData['data'] ?? null,
                'recipient' => $phoneNumber,
                'message' => $message
            ];
        } catch (\Exception $e) {
            Log::error('SMS API call failed', [
                'phone' => $phoneNumber,
                'error' => $e->getMessage()
            ]);

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    private function cleanPhoneNumber($phoneNumber)
    {
        // Handle null or empty values
        if (empty($phoneNumber)) {
            return null;
        }

        // Remove any non-digit characters
        $cleaned = preg_replace('/\D/', '', $phoneNumber);

        // Handle different formats
        if (strlen($cleaned) == 10 && substr($cleaned, 0, 1) == '0') {
            // Format: 0712345678 -> 254712345678
            return '254' . substr($cleaned, 1);
        } elseif (strlen($cleaned) == 10 && substr($cleaned, 0, 3) == '254') {
            // Format: 254712345678 -> 254712345678
            return $cleaned;
        } elseif (strlen($cleaned) == 9 && substr($cleaned, 0, 1) != '0') {
            // Format: 712345678 -> 254712345678
            return '254' . $cleaned;
        } elseif (strlen($cleaned) == 12 && substr($cleaned, 0, 3) == '254') {
            // Format: 254712345678 (already correct)
            return $cleaned;
        }

        return null;
    }

    private function logSms($ticket, $message, $result)
    {
        try {
            SmsLog::create([
                'contact_name' => $ticket->first_name . ' ' . $ticket->last_name,
                'phone_number' => $ticket->phone,
                'school_name' => $ticket->school,
                'message_content' => $message,
                'campaign_name' => 'CSV Processor - Ticket Confirmation',
                'parts' => ceil(strlen($message) / 160),
                'status' => $result['success'] ? 'sent' : 'failed',
                'message_id' => $result['message_id'] ?? null,
                'cost' => 1.00, // Default cost
                'sent_by' => Auth::check() ? Auth::id() : 1, // Default to admin user
                'error_data' => $result['success'] ? null : json_encode(['error' => $result['error']])
            ]);
        } catch (\Exception $e) {
            Log::error('Failed to log SMS', [
                'ticket_id' => $ticket->id,
                'error' => $e->getMessage()
            ]);
        }
    }
}
