<?php

namespace App\Services\Whmcs;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Fetches WHMCS ticket attachments via the GetTicketAttachments admin API
 * and caches the binary in `ticket_attachment_cache`. Used by:
 *   - the portal's image lightbox (returns base64-decoded bytes for display)
 *   - the AI vision pipeline (passes base64 to Claude as image content)
 *
 * WHMCS GetTicketAttachments returns the file as base64 in the `data` field.
 * Cache TTL is 7 days — re-fetched on next miss past that.
 */
class AttachmentFetcher
{
    public function __construct(private WhmcsClient $whmcs) {}

    /**
     * Fetch (or return cached) attachment binary from WHMCS via the
     * GetTicketAttachment API. Returns:
     *   ['filename', 'mime_type', 'size_bytes', 'data_base64']
     * or null on failure.
     *
     * $relatedType : 'ticket' | 'reply' | 'note'
     * $key         : "<whmcs_id>:<index>" — WHMCS GetTicket gives us the
     *                index per file but no stable attachment id; this composite
     *                lets the cache table dedupe per (ticket, related, index).
     */
    public function fetch(int $localTicketId, string $relatedType, string $key, string $filename = ''): ?array
    {
        $cached = DB::table('ticket_attachment_cache')
            ->where('ticket_id', $localTicketId)
            ->where('whmcs_attachment_id', $key)
            ->where('related_type', $relatedType)
            ->first();

        $fresh = $cached
            && $cached->data_base64
            && $cached->fetched_at
            && strtotime($cached->fetched_at) > (time() - 7 * 86400);
        if ($fresh) return (array) $cached;

        // Parse the composite key.
        [$relatedId, $index] = array_pad(explode(':', $key, 2), 2, '0');

        // WHMCS GetTicketAttachment param shape:
        //   relatedid (int) | type ('ticket'|'reply'|'note') | index (int).
        // The param is 'type', NOT 'relatedtype' (a common doc confusion).
        $resp = $this->whmcs->call('GetTicketAttachment', [
            'relatedid' => $relatedId,
            'type'      => $relatedType,
            'index'     => (int) $index,
        ]);

        if (! $resp || ($resp['result'] ?? '') !== 'success') {
            Log::warning('hsap.whmcs.attachment_fetch_failed', [
                'ticket' => $localTicketId, 'key' => $key,
                'msg' => $resp['message'] ?? null,
            ]);
            return null;
        }

        $data = (string) ($resp['data'] ?? '');
        $name = (string) ($resp['filename'] ?? $filename ?: 'attachment');
        $mime = $this->guessMime($name);
        $size = strlen(base64_decode($data, true) ?: '');

        DB::table('ticket_attachment_cache')->updateOrInsert(
            [
                'ticket_id'           => $localTicketId,
                'whmcs_attachment_id' => $key,
                'related_type'        => $relatedType,
            ],
            [
                'filename'    => substr($name, 0, 250),
                'mime_type'   => $mime,
                'size_bytes'  => $size,
                'data_base64' => $data,
                'fetched_at'  => now(),
                'created_at'  => now(),
                'updated_at'  => now(),
            ],
        );

        return (array) DB::table('ticket_attachment_cache')
            ->where('ticket_id', $localTicketId)
            ->where('whmcs_attachment_id', $key)
            ->where('related_type', $relatedType)
            ->first(['filename', 'mime_type', 'size_bytes', 'data_base64']);
    }

    public function isImage(string $mime): bool
    {
        return str_starts_with($mime, 'image/');
    }

    private function guessMime(string $filename): string
    {
        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        return [
            'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png',
            'gif' => 'image/gif', 'webp' => 'image/webp', 'bmp' => 'image/bmp',
            'pdf' => 'application/pdf', 'txt' => 'text/plain',
            'log' => 'text/plain', 'json' => 'application/json',
            'zip' => 'application/zip',
        ][$ext] ?? 'application/octet-stream';
    }
}
