<?php

namespace App\Services;

use Exception;
use chillerlan\QRCode\{QRCode, QROptions};
use Illuminate\Support\Facades\Log;
use KlaviyoAPI\KlaviyoAPI;

/**
 * Klaviyo - Campaing helper service
 */
class KlaviyoService
{
    protected $key;
    protected $privateKey;
    protected $eventRegistrationList;
    protected $eventRegistrationVipList;
    protected $eventRegistrationVipToProcessList;
    protected $eventRegistrationVipList2;
    protected $eventRegistrationVipToProcessList2;
    protected KlaviyoAPI $klaviyo;

    public function __construct()
    {
        $this->key = config('services.klaviyo.key');
        $this->privateKey = config('services.klaviyo.private_key');
        $this->eventRegistrationList = config('services.klaviyo.event_registration_list');
        $this->eventRegistrationVipList = config('services.klaviyo.event_registration_vip_list');
        $this->eventRegistrationVipToProcessList = config('services.klaviyo.event_registration_vip_to_process_list');
        $this->eventRegistrationVipList2 = config('services.klaviyo.event_registration_vip_list_2');
        $this->eventRegistrationVipToProcessList2 = config('services.klaviyo.event_registration_vip_to_process_list_2');

        $this->klaviyo = new KlaviyoAPI(
            $this->privateKey,
            30);
    }

    /**
     * Process Pending invitation lists
     *
     * @return void
     */
    public function processLists()
    {
        Log::info('Event Registration - Checking VIP 1...');
        $this->eventProcessList($this->eventRegistrationVipToProcessList, $this->eventRegistrationVipList);

        Log::info('Event Registration - Checking VIP 2...');
        $this->eventProcessList($this->eventRegistrationVipToProcessList2, $this->eventRegistrationVipList2);
    }

    /**
     * Processes pending profiles in klaviyo to process list (manually added profiles)
     *
     * @param string $sourceList
     * @param string $targetList
     *
     * @return void
     */
    protected function eventProcessList($sourceList, $targetList)
    {
        if (!$sourceList || !$sourceList) {
            Log::warning('Event Registration - Lists not set');
            return;
        }
        Log::info('Event Registration - Checking pending list...');
        $response = $this->klaviyo->Lists->getListProfiles($sourceList, null, null, null, null, 100);

        $profiles = $response['data'];

        Log::info('Event Registration - Found ' . sizeof($profiles) . ' profiles to process.');
        foreach($profiles as $profile) {
            try {
                $this->_eventProcessProfile($profile, $sourceList, $targetList);
                Log::info('Event Registration - Successfully registered profile ' . $profile['id']);
            } catch (Exception $e) {
                Log::error('Event Registration Error - ' . $profile['id'] . ' - ' . $e->getMessage());
            }
        }
    }

    /**
     * Registers email to event list
     *
     * @param string $email
     * @param string $lang
     * @return bool status
     */
    public function eventRegisterUser(string $email, string $lang, bool $acceptsMarketing)
    {
        if (!$this->eventRegistrationList) {
            Log::warning('Event Registration - List not set');
            return false;
        }
        $qrcode = $this->_generateQrCode($email);

        $data = [
            'type' => 'profile',
            'attributes' => [
                'email' => $email,
                'properties' => [
                    'language' => $lang,
                    'qrcode'    => url("qrcodes/$qrcode.png"),
                    'qrcodeId'  => $qrcode,
                    'Accepts Marketing' => $acceptsMarketing,
                ],
            ]
        ];

        $success = false;
        try {
            $profiles = $this->klaviyo->Profiles->getProfiles(null, null, $filter = "any(email,[\"$email\"])");
            if (!empty($profiles['data'])) {
                $data['id'] = $profiles['data'][0]['id'];
                $profile = $this->klaviyo->Profiles->updateProfile($profiles['data'][0]['id'], ['data' => $data])['data'];
            } else {
                $profile = $this->klaviyo->Profiles->createProfile(['data' => $data])['data'];
            }
            if ($acceptsMarketing) {
                $this->klaviyo->Profiles->subscribeProfiles([
                    'data' => [
                        'type' => 'profile-subscription-bulk-create-job',
                        'attributes' => [
                            'profiles' => [
                                'data' => [
                                    [
                                        'type' => 'profile',
                                        'id' => $profile['id'],
                                        'attributes' => [
                                            'email' => $email,
                                            'subscriptions' => [
                                                'email' => [
                                                    'marketing' => [
                                                        'consent' => 'SUBSCRIBED',
                                                    ]
                                                ]
                                            ],
                                        ]
                                    ]
                                ]
                            ]
                        ],
                        'relationships' => [
                            'list' => [
                                'data' => [
                                    'type' => 'list',
                                    'id' => $this->eventRegistrationList
                                ]
                            ]
                        ]
                    ]
                ]);
            } else {
                $this->klaviyo->Lists->createListRelationships(
                    $this->eventRegistrationList,
                    ['data' => [['type' => 'profile', 'id' => $profile['id']]]]);
            }
            $success = true;
            Log::info('Event Registration (single) - Registered profile ' . $qrcode);
        } catch (Exception $e) {
            $this->logKlaviyoError('Event Registration', $e, ['email' => $email, 'qrcode' => $qrcode]);
            Log::error('Event Registration (single) FAILED - profile ' . $qrcode);
        }

        return $success;
    }

    /**
     * Subscribes user to back in stock notice for a given product variant
     *
     * @param array $data
     * @return boolean succcess
     */
    public function subscribeBackInStock($data)
    {
        $listId = config('services.klaviyo.back_in_stock_list');

        $profileId = $this->subscribeList($listId, $data['email'], !empty($data['lang']) ? $data['lang'] : 'pt-PT');

        if (!$profileId) {
            return false;
        }

        try {
            $body = [
                'data' => [
                    'type' => 'back-in-stock-subscription',
                    'attributes' => [
                        'channels' => ['EMAIL'],
                        'profile' => [
                            'data' => [
                                'type' => 'profile',
                                'id' => $profileId,
                                'attributes' => [
                                    'email' => $data['email']
                                ]
                            ]
                        ]
                    ],
                    'relationships' => [
                        'variant' => [
                            'data' => [
                                'type' => 'catalog-variant',
                                'id' => '$shopify:::$default:::' . $data['variant']
                            ]
                        ]
                    ]
                ]
            ];
            $this->klaviyo->Catalogs->createBackInStockSubscription($body);
        } catch (Exception $e) {
            $this->logKlaviyoError('Back in stock subscribe', $e, ['email' => $data['email'], 'variant' => $data['variant']]);
            return false;
        }
        return true;
    }

    /**
     * Subscribes user to list
     *
     * @param array $data
     * @return string|false profileId
     */
    public function subscribeList($listId, $email, $lang = 'pt-PT', $acceptsMarketing = true)
    {
        $data = [
            'type' => 'profile',
            'attributes' => [
                'email' => $email,
                'properties' => [
                    'language' => $lang,
                    'Accepts Marketing' => $acceptsMarketing,
                ],
            ]
        ];

        $success = false;
        try {
            $profiles = $this->klaviyo->Profiles->getProfiles(null, null, $filter = "any(email,[\"$email\"])");
            if (!empty($profiles['data'])) {
                $data['id'] = $profiles['data'][0]['id'];
                $profile = $this->klaviyo->Profiles->updateProfile($profiles['data'][0]['id'], ['data' => $data])['data'];
            } else {
                $profile = $this->klaviyo->Profiles->createProfile(['data' => $data])['data'];
            }
            if ($acceptsMarketing) {
                $this->klaviyo->Profiles->subscribeProfiles([
                    'data' => [
                        'type' => 'profile-subscription-bulk-create-job',
                        'attributes' => [
                            'profiles' => [
                                'data' => [
                                    [
                                        'type' => 'profile',
                                        'id' => $profile['id'],
                                        'attributes' => [
                                            'email' => $email,
                                            'subscriptions' => [
                                                'email' => [
                                                    'marketing' => [
                                                        'consent' => 'SUBSCRIBED',
                                                    ]
                                                ]
                                            ],
                                        ]
                                    ]
                                ]
                            ]
                        ],
                        'relationships' => [
                            'list' => [
                                'data' => [
                                    'type' => 'list',
                                    'id' => $listId
                                ]
                            ]
                        ]
                    ]
                ]);
            } else {
                $this->klaviyo->Lists->createListRelationships(
                    $listId,
                    ['data' => [['type' => 'profile', 'id' => $profile['id']]]]
                );
            }
            $success = $profile['id'];
            Log::info('Klaviyo - User subscribed to list (list id: ' . $listId . ', profileId: ' . $profile['id'] . ')');        } catch (Exception $e) {
            $this->logKlaviyoError('Subscribe to list', $e, ['listId' => $listId, 'email' => $email]);
            Log::error('Klaviyo - Error Subscribing user to list (list id: ' . $listId . ')');
        }

        return $success;
    }


    /**
     * Generates uuid as the single registration code and generates correspondent qrcode (image)
     * @param string $email
     * @return string
     */
    protected function _generateQrCode(string $email)
    {
        $qrcodeOptions = new QROptions([
            'addQuietzone' => false
        ]);
        $qrObject = new QRCode($qrcodeOptions);
        $qrcode = md5($email . "-area-event-admission");
        if (!file_exists(public_path("qrcodes/$qrcode.png"))) {
            $qrObject->render($qrcode, public_path("qrcodes/$qrcode.png"));
        }
        return $qrcode;
    }

    /**
     * Processes Klaviyo pending to process profile:
     * - adds qrcode and image location to profile
     * - removes profile from to process list
     * - adds profile to registered users list - triggers email invitation
     *
     * @param array $profile
     * @param string $sourceList
     * @param string $targetList
     * @return void
     */
    protected function _eventProcessProfile($profile, $sourceList, $targetList)
    {
        if (empty($profile['attributes']['email'])) {
            return;
        }
        $qrcode = $this->_generateQrCode($profile['attributes']['email']);

        $updateProfileData = [
            'data' => [
                'type' => 'profile',
                'id' => $profile['id'],
                'attributes' => [
                    'properties' => [
                        'qrcode'    => url("qrcodes/$qrcode.png"),
                        'qrcodeId'  => $qrcode
                    ]
                ]
            ]
        ];

        // update profile with qrcode data
        $this->klaviyo->Profiles->updateProfile($profile['id'], $updateProfileData);

        // add to send list
        $this->klaviyo->Lists->createListRelationships(
            $targetList,
            ['data' => [['type' => 'profile', 'id' => $profile['id']]]]);


        // remove from to process list
        $this->klaviyo->Lists->deleteListRelationships(
            $sourceList,
            ['data' => [['type' => 'profile', 'id' => $profile['id']]]]);
    }

    /**
     * Log comprehensive Klaviyo API error information
     *
     * @param string $context
     * @param Exception $e
     * @param array $additionalData
     * @return void
     */
    protected function logKlaviyoError($context, Exception $e, $additionalData = [])
    {
        $errorData = [
            'context' => $context,
            'message' => $e->getMessage(),
            'code' => $e->getCode(),
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'additional_data' => $additionalData
        ];

        // Try to get HTTP response details if available
        try {
            if ($e instanceof \KlaviyoAPI\ApiException) {
                $errorData['http_response_body'] = $e->getResponseBody();
            }
        } catch (Exception $responseException) {
            // If we can't get response details, just note that
            $errorData['response_error'] = 'Could not retrieve HTTP response details';
        }

        // Check if there's a previous exception
        if ($e->getPrevious()) {
            $errorData['previous_exception'] = [
                'message' => $e->getPrevious()->getMessage(),
                'code' => $e->getPrevious()->getCode(),
            ];
        }

        Log::error('Klaviyo API Error Details:', $errorData);

        // Also log the stack trace for debugging
        Log::debug('Klaviyo Error Stack Trace: ' . $e->getTraceAsString());
    }
}
