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

class Filesr2 extends CI_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->database();
        $this->load->model('CommonModel');
        $this->load->library(['pagination','response','ValidateData','core/R2Storage']);
        $this->load->helper(['url','security']);
    }

    /* =========================================================
     * FILE LIST
     * ========================================================= */
    public function fileList()
    {
        $this->access->checkTokenKey();
        $this->response->decodeRequest();

        $where = [];
        $orderBy = $this->input->post('orderBy') ?: 'created_date';
        $order   = $this->input->post('order') ?: 'DESC';

        foreach (['cmp_type','record_id','folderID'] as $f) {
            if ($this->input->post($f)) {
                $key = $f === 'folderID' ? 'folder_id' : $f;
                $where["{$key} = "] = "'".$this->input->post($f)."'";
            }
        }

        if (empty($where['folder_id'])) {
            $where['folder_id'] = 'IS NULL';
        }

        $config = $this->config->item('pagination');
        $config['total_rows'] =
            $this->CommonModel->getCountByParameter('media_id','media',$where);

        $this->pagination->initialize($config);

        $page = (int)$this->input->post('curpage') * $config['per_page'];

        $rows = $this->CommonModel->GetMasterListDetails(
            '',
            'media',
            $where,
            $config['per_page'],
            $page,
            [],
            ['orderBy'=>$orderBy,'order'=>$order]
        );

        $data = [];
        foreach ($rows as $row) {
            $data[] = $this->mapMediaRow($row);
        }

        $this->response->output([
            'flag'=>'S',
            'data'=>$data,
            'paginginfo'=>[
                'curPage'=>(int)$this->input->post('curpage'),
                'totalRecords'=>$config['total_rows']
            ]
        ],200);
    }

    // private function mapMediaRow($row)
    // {
    //     $token = rtrim(strtr(
    //         base64_encode($row->media_id.'|'.$row->company_id),
    //         '+/','-_'
    //     ),'=');
        
    //     $mime = $row->mime_type ?: 'application/octet-stream';
    //     $streamable = str_starts_with($mime,'video/') || str_starts_with($mime,'audio/');

    //     return [
    //         'id'=>$row->media_id,
    //         'name'=>$row->media_key,
    //         'mimeType'=>$mime,
    //         'fileType'=>$row->media_type,
    //         'createdAt'=>$row->created_date,
    //         'token'=>$token,
    //         'viewUrl'=>$streamable ? null : base_url("filesr2/view/$token"),
    //         'downloadUrl'=>base_url("filesr2/download/$token"),
    //         'streamUrl'=>$streamable ? base_url("filesr2/stream/$token") : null
    //     ];
    // }
    private function mapMediaRow($row)
    {
        $token = rtrim(strtr(
            base64_encode($row->media_id.'|'.$row->company_id),
            '+/','-_'
        ),'=');

        $mime = $row->mime_type ?: 'application/octet-stream';
        $mediaType = $row->media_type ?? 'file';

        $isVideo = str_starts_with($mime, 'video/');
        $isAudio = str_starts_with($mime, 'audio/');
        $isImage = str_starts_with($mime, 'image/');

        // Build base URLs
        $baseView     = base_url("filesr2/view/$token");
        $baseDownload = base_url("filesr2/download/$token");
        $baseStream   = base_url("filesr2/stream/$token");

        // Thumbnail & poster URLs
        $thumbUrl  = null;
        $posterUrl = null;

        if ($isImage || $isVideo) {
            $thumbUrl = base_url("filesr2/thumb/$token");
        }

        if ($isVideo) {
            $posterUrl = base_url("filesr2/poster/$token");
        }

        return [
            'id'           => $row->media_id,
            'name'         => $row->media_key,
            'mimeType'     => $mime,
            'fileType'     => $mediaType,
            'createdAt'    => $row->created_date,
            'token'        => $token,

            // URLs
            'thumbnailUrl' => $thumbUrl,
            'posterUrl'    => $posterUrl,

            'viewUrl'      => (!$isVideo && !$isAudio) ? $baseView : null,
            'downloadUrl'  => $baseDownload,
            'streamUrl'    => ($isVideo || $isAudio) ? $baseStream : null,
        ];
    }


    /* =========================================================
     * VIEW / DOWNLOAD / STREAM
     * ========================================================= */

    public function view($token)
    {
        $file = $this->resolveFile($token);
        $this->outputFile($file,'inline');
    }

    public function download($token)
    {
        $file = $this->resolveFile($token);
        $this->outputFile($file,'attachment');
    }

    public function stream($token)
    {
        $file = $this->resolveFile($token);
        $url  = $this->r2storage->presign($file['r2_key'],'+10 minutes');
        redirect($url);
    }
    public function thumb($token)
    {
        $file = $this->resolveFile($token);
        $file['r2_key'] = dirname($file['r2_key']) . '/thumb_' . basename($file['r2_key']);
        
        $this->outputFile($file, 'image/jpeg');
    }

    public function poster($token)
    {
        $file = $this->resolveFile($token);
        $file['r2_key'] = dirname($file['r2_key']) . '/poster_' . basename($file['r2_key']) . '.jpg';

        $this->outputFile($file, 'image/jpeg');
    }

    /* =========================================================
     * DELETE
     * ========================================================= */

    public function deleteFile()
    {
        $this->access->checkTokenKey();
        $this->response->decodeRequest();

        $fileId = (int)$this->input->post('file_id');

        $file = $this->CommonModel->getMasterDetails(
            'media',
            '*',
            ['media_id' => $fileId, 'company_id' => $this->company_id]
        );

        if (!$file) {
            return $this->response->output([
                'flag' => 'F',
                'msg'  => 'File not found'
            ], 404);
        }

        // Build R2 key
        $r2Key = $this->buildR2Key(
            $file[0]->media_key,
            $file[0]->company_id
        );

        /* -----------------------------------------
        * Delete original file
        * ----------------------------------------- */
        $this->r2storage->delete($r2Key);

        /* -----------------------------------------
        * Delete thumbnail (if exists)
        * ----------------------------------------- */
        $thumbKey = dirname($r2Key) . '/thumb_' . basename($r2Key);
        $this->r2storage->delete($thumbKey);

        /* -----------------------------------------
        * Delete video poster (if exists)
        * ----------------------------------------- */
        $posterKey = dirname($r2Key) . '/poster_' . basename($r2Key) . '.jpg';
        $this->r2storage->delete($posterKey);

        /* -----------------------------------------
        * Delete DB record
        * ----------------------------------------- */
        $this->CommonModel->deleteMasterDetails(
            'media',
            ['media_id' => $fileId, 'company_id' => $this->company_id]
        );

        return $this->response->output([
            'flag' => 'S',
            'msg'  => 'File, thumbnail and poster deleted successfully'
        ], 200);
    }


    /* =========================================================
     * CORE HELPERS
     * ========================================================= */

    private function resolveFile(string $token): array
    {
        $decoded = base64_decode(strtr($token,'-_','+/'));
        if (!$decoded || !str_contains($decoded,'|')) {
            $this->error('Invalid token',400);
        }

        [$id,$companyId] = explode('|',$decoded);

        $file = $this->CommonModel->getMasterDetails(
            'media','*',['media_id'=>$id]
        );

        if (!$file) {
            $this->error('File not found',404);
        }

        return [
            'original_name'=>$file[0]->original_name,
            'mime'=>$file[0]->mime_type,
            'size'=>$file[0]->file_size,
            'r2_key'=>$this->buildR2Key($file[0]->media_key,$companyId)
        ];
    }

    private function buildR2Key(string $fileName,int $companyId): string
    {
        $tenant = getTenantKey();
        $company = getCompanyKey($companyId);

        return
            "tenant_{$tenant['tenant_key']}/".
            "company_{$company['company_key']}/files/".
            $fileName;
    }

    // private function outputFile(array $file,string $disposition)
    // {
    //     $obj = $this->r2storage->get($file['r2_key']);

    //     header("Content-Type: {$file['mime']}");
    //     header("Content-Length: {$file['size']}");
    //     header("Content-Disposition: {$disposition}; filename=\"{$file['original_name']}\"");
    //     header("X-Content-Type-Options: nosniff");

    //     echo $obj['Body'];
    //     exit;
    // }
    private function outputFile(array $file, string $disposition)
    {
        try {
            $obj = $this->r2storage->get($file['r2_key']);
            $stream = $obj['Body']; // StreamInterface

            header("Content-Type: {$file['mime']}");
            header("Content-Disposition: {$disposition}; filename=\"{$file['original_name']}\"");
            header("X-Content-Type-Options: nosniff");
            header("Accept-Ranges: bytes");

            if ($disposition === "attachment") {
                header("Cache-Control: private, no-store");
            } else {
                header("Cache-Control: public, max-age=31536000, immutable");
                header("ETag: \"" . md5($file['r2_key']) . "\"");
            }

            if (isset($obj['LastModified'])) {
                header("Last-Modified: " . gmdate(
                    "D, d M Y H:i:s",
                    strtotime($obj['LastModified'])
                ) . " GMT");
            }

            if (isset($obj['ContentLength'])) {
                header("Content-Length: {$obj['ContentLength']}");
            }

            while (!$stream->eof()) {
                echo $stream->read(8192);
                flush();
            }

            exit;
        } catch (Exception $e) {
            log_message('error', 'R2 output error: '.$e->getMessage());
            $this->respondError('Unable to read file', 500);
        }
    }



    private function error(string $msg,int $code)
    {
        http_response_code($code);
        echo json_encode(['error'=>$msg]);
        exit;
    }
    /* =========================================================
    * UPLOAD FILES (R2)
    * ========================================================= */
    public function uploadFiles($folderId = null)
    {
        $this->access->checkTokenKey();
        $this->response->decodeRequest();

        $extraData = [];

        // Optional params (same as old controller)
        $cmsType   = $_GET['cmsType'] ?? null;
        $module    = $this->input->post('module');
        $record_id = $this->input->post('record_id');
        $source = $this->input->post('source') ?? 'local';
        $temp_reference_id = $this->input->post('temp_reference_id') ?? null;
        
        if (!empty($cmsType)) {
            $extraData['cmp_type'] = $cmsType;
        }

        /* ---------------------------------------
        * Tenant resolution
        * --------------------------------------- */
        $tenantRes = getTenantKey();
        if ($tenantRes['flag'] === 'F') {
            return $this->response->output($tenantRes, 200);
        }

        /* ---------------------------------------
        * Company resolution
        * --------------------------------------- */
        $companyRes = getCompanyKey($this->company_id);
        if ($companyRes['flag'] === 'F') {
            return $this->response->output($companyRes, 200);
        }

        /* ---------------------------------------
        * Optional folder mapping (DB only)
        * --------------------------------------- */
        if (!empty($folderId) && $folderId != 0) {
            $folder = $this->CommonModel->getMasterDetails(
                'media',
                '*',
                ['media_id' => $folderId]
            );

            if (empty($folder)) {
                return $this->response->output([
                    'flag' => 'F',
                    'msg'  => 'Invalid folder'
                ], 400);
            }

            // purely DB-level grouping
            $extraData['folder_id'] = $folderId;
        }

        /* ---------------------------------------
        * Load R2 uploader
        * --------------------------------------- */
        $this->load->library('core/RealtimeUploadR2');

        /* ---------------------------------------
        * Upload settings (same contract as old)
        * --------------------------------------- */
        $settings = [
            'extension' => [
                'webp','png','jpg','jpeg','gif','svg',
                'pdf','doc','docx','xls','xlsx',
                'mp3','wav','ogg',
                'mp4','avi','mkv'
            ],
            'maxFileSize'     => 10485760, // 10MB
            'rename'          => true,
            'uniqueFilename'  => false,
            'source'=>$source,
            // DB
            'dbTable'         => 'media',
            'fileTypeColumn'  => 'media_type',
            'fileColumn'      => 'media_key',
            'isSaveToDB'      => 'Y',

            // Tenant context
            'company_id'      => $this->company_id,

            // Optional linkage
            'module'          => $module,
            'record_id'       => $record_id,
            'temp_reference_id'       => $temp_reference_id,
            
            // Extra DB fields
            'extraData'       => $extraData,
        ];

        /* ---------------------------------------
        * Start upload (FILES → TMP → R2 → DB)
        * --------------------------------------- */
        $result = $this->realtimeuploadr2->init($settings);
        if($result){
            $this->response->output([
                'flag' => 'S',
                'data' => $result
            ], 200);
        }
    }

}
