<?php
defined('BASEPATH') or exit('No direct script access allowed');

require FCPATH . 'vendor/autoload.php';

use GuzzleHttp\Client;
use Kreait\Firebase\Factory;
use Google\Cloud\Firestore\FirestoreClient;

class Firebase
{
    protected $firestore;
    protected $storage;

    public function __construct()
    {
        // Path to your service account JSON
        $serviceAccountPath = APPPATH . 'config/ringsideproduction.json';

        try {
            // Initialize Firebase Factory
            $factory = (new Factory)->withServiceAccount($serviceAccountPath)
                ->withDefaultStorageBucket('ringsideproduction.firebasestorage.app');


            // Initialize Firestore
            $this->firestore = $factory->createFirestore()->database();

            // Initialize Storage
            $this->storage = $factory->createStorage();
        } catch (\Exception $e) {
            log_message('error', 'Firebase init failed: ' . $e->getMessage());
            $this->firestore = null;
            $this->storage = null;
        }
    }

    // Get Firestore database reference
    public function db()
    {
        return $this->firestore;
    }
    public function generateDocumentId($collection)
    {
        return $this->firestore->collection($collection)->newDocument()->id();
    }


    // Optional: helper to set document data and return Firestore generated ID
    public function setDocument($collection, $data)
    {
        if (!$this->firestore)
            return false;
        $docRef = $this->firestore->collection($collection)->add($data);
        return $docRef->id();
    }
    public function setDocumentWithId($collection, $id, $data)
    {
        if (!$this->firestore)
            return false;
        $this->firestore->collection($collection)->document($id)->set($data); // fixed ID
        return $id;
    }

    // Optional: helper to get document data
    public function getDocument($collection, $documentId)
    {
        if (!$this->firestore)
            return null;

        $docRef = $this->firestore->collection($collection)->document($documentId);
        $snapshot = $docRef->snapshot();

        return $snapshot->exists() ? $snapshot->data() : null;
    }

    // Optional: helper to get all documents in a collection
    public function getCollection($collection)
    {
        if (!$this->firestore)
            return [];

        $docs = $this->firestore->collection($collection)->documents();
        $result = [];
        foreach ($docs as $doc) {
            $result[$doc->id()] = $doc->data();
        }
        return $result;
    }

    public function updateDocument($collection, $documentId, $data)
    {
        if (!$this->firestore)
            return false;

        $docRef = $this->firestore->collection($collection)->document($documentId);
        $docRef->set($data, ['merge' => true]);

        return true;
    }

    public function uploadFile($file, $destination)
    {
        if (!$this->storage) {
            log_message('error', 'Firebase Storage not initialized');
            return false;
        }

        try {
            $bucket = $this->storage->getBucket();
            $object = $bucket->upload(
                fopen($file, 'r'),
                [
                    'name' => $destination
                ]
            );

            // Get public URL
            return $object->signedUrl(new \DateTime('+100 years'));
        } catch (\Exception $e) {
            log_message('error', 'Firebase upload error: ' . $e->getMessage());
            return false;
        }
    }

    public function deleteFile($path)
    {
        if (!$this->storage) {
            log_message('error', 'Firebase Storage not initialized');
            return false;
        }

        try {
            $bucket = $this->storage->getBucket();
            $object = $bucket->object($path);
            $object->delete();
            return true;
        } catch (\Exception $e) {
            log_message('error', 'Firebase delete error: ' . $e->getMessage());
            return false;
        }
    }

    public function deleteDocument($collection, $documentId)
    {
        if (!$this->firestore)
            return false;

        $docRef = $this->firestore->collection($collection)->document($documentId);
        $docRef->delete();

        return true;
    }
    /**
     * Set document using FULL document path
     * Example path:
     * events/{eventId}/Session_Packets/{docId}
     */
    public function setDocumentByPath($documentPath, array $data)
    {
        return $this->firestore
            ->document($documentPath)
            ->set($data);
    }
    /**
     * List all subcollections under a Firestore document
     *
     * @param string $collection The top-level collection (e.g., 'events')
     * @param string $documentId The document ID
     * @return array List of subcollection names
     */
    public function listSubcollections($collection, $documentId)
    {
        $docRef = $this->firestore->collection($collection)->document($documentId);

        // Get CollectionReference objects
        $subcollections = $docRef->collections();

        $names = [];
        foreach ($subcollections as $subcol) {
            $names[] = $subcol->id(); // collection name
        }

        return $names;
    }

    public function sendFCMNotification(
        $token,
        $title,
        $body,
        $eventId = null,
        $conversationId = null
    ) {
        $serviceAccountPath = APPPATH . 'config/ringsideproduction.json';
        $serviceAccount = json_decode(file_get_contents($serviceAccountPath), true);
        $projectId = $serviceAccount['project_id'];

        $scopes = ['https://www.googleapis.com/auth/firebase.messaging'];

        // Correct credentials creation
        $credentials = new \Google\Auth\Credentials\ServiceAccountCredentials($scopes, $serviceAccount);
        $accessToken = $credentials->fetchAuthToken()['access_token'];

        $url = "https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send";

        $client = new \GuzzleHttp\Client();
        if ($eventId && $conversationId) {
            $message = [
                'message' => [
                    'token' => $token,
                    'notification' => [
                        'title' => $title,
                        'body' => $body
                    ],
                    'data' => [
                        'event_id'        => (string) $eventId,
                        'conversation_id' => (string) $conversationId,
                    ]
                ]
            ];
        } else {
            $message = [
                'message' => [
                    'token' => $token,
                    'notification' => [
                        'title' => $title,
                        'body' => $body
                    ]
                ]
            ];
        }


        try {
            $response = $client->post($url, [
                'headers' => [
                    'Authorization' => 'Bearer ' . $accessToken,
                    'Content-Type' => 'application/json'
                ],
                'body' => json_encode($message)
            ]);

            return json_decode($response->getBody(), true);
        } catch (\Exception $e) {
            log_message('error', 'FCM send error: ' . $e->getMessage());
            return false;
        }
    }
    public function generateSignedUrl($filePath, $expires = 3600)
    {
        if (!$this->storage) return false;

        try {
            // Clean the path: remove leading slashes
            $filePath = ltrim($filePath, '/');

            $bucket = $this->storage->getBucket();
            $object = $bucket->object($filePath);

            if (!$object->exists()) {
                log_message('error', 'File does not exist in storage: ' . $filePath);
                return false;
            }

            return $object->signedUrl(
                new \DateTime("+{$expires} seconds"),
                ['version' => 'v4']
            );
        } catch (\Exception $e) {
            log_message('error', 'Failed to generate signed URL: ' . $e->getMessage());
            return false;
        }
    }

    public function saveAdminFcmToken($token)
    {
        $adminId = 'f9HX2UFr8w1EVn3U1L7N';
        if (!$adminId || !$token) return false;



        return $this->updateDocument('admin', $adminId, ['token' => $token]);
    }
}
