<?php

declare(strict_types=1);

namespace App\Domain\Media;

use App\Models\Article;
use App\Models\Attachment;
use App\Settings\GeneralSettings;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\ImageManager;
use RuntimeException;

/**
 * Template-rendered OG covers (1200×630) written to the attachments disk.
 * Uses title + summary; does not call an external text-to-image API.
 */
class ArticleCoverGenerator
{
    public function generate(Article $article): array
    {
        $disk = (string) config('larablog.attachments_disk', 'attachments');
        $relative = sprintf(
            'covers/%s/article-%d-%s.jpg',
            now()->format('Y/m'),
            $article->id,
            substr(sha1($article->title.'|'.microtime(true)), 0, 10),
        );

        $binary = $this->renderJpeg($article);
        Storage::disk($disk)->put($relative, $binary, ['visibility' => 'public']);

        Attachment::query()->create([
            'article_id' => $article->id,
            'disk' => $disk,
            'path' => $relative,
            'filename' => basename($relative),
            'mime' => 'image/jpeg',
            'size' => strlen($binary),
            'checksum' => hash('sha256', $binary),
            'visibility' => Attachment::VISIBILITY_PUBLIC,
            'synced_at' => now(),
        ]);

        return [
            'disk' => $disk,
            'path' => $relative,
            'source' => ArticleCoverService::SOURCE_GENERATED,
        ];
    }

    protected function renderJpeg(Article $article): string
    {
        $manager = new ImageManager(new Driver);
        $image = $manager->create(1200, 630)->fill('#0f3d4c');

        // Soft bands for atmosphere (avoid a single flat fill).
        $image->drawRectangle(0, 0, function ($rect): void {
            $rect->size(1200, 210)->background('#123f4f');
        });
        $image->drawRectangle(0, 420, function ($rect): void {
            $rect->size(1200, 210)->background('#16384a');
        });
        $image->drawRectangle(0, 0, function ($rect): void {
            $rect->size(1200, 12)->background('#2bb0a6');
        });

        $site = 'LaraBlog';
        try {
            $site = (string) (app(GeneralSettings::class)->site_name ?: $site);
        } catch (\Throwable) {
            //
        }

        $title = $this->wrapText((string) $article->title, 18, 3);
        $summary = trim((string) ($article->ai_summary ?: $article->description ?: ''));
        if ($summary !== '') {
            $summary = $this->wrapText($summary, 32, 2);
        }

        $font = $this->fontFile();

        if ($font !== null) {
            $image->text($site, 72, 110, function ($f) use ($font): void {
                $f->filename($font);
                $f->size(28);
                $f->color('#8fd9d2');
            });

            $image->text($title, 72, 220, function ($f) use ($font): void {
                $f->filename($font);
                $f->size(56);
                $f->color('#f4f7f8');
                $f->lineHeight(1.25);
            });

            if ($summary !== '') {
                $image->text($summary, 72, 430, function ($f) use ($font): void {
                    $f->filename($font);
                    $f->size(26);
                    $f->color('#c5d4db');
                    $f->lineHeight(1.35);
                });
            }
        }

        $encoded = $image->toJpeg(85)->toString();

        if (! is_string($encoded) || $encoded === '') {
            throw new RuntimeException('Failed to encode generated cover JPEG.');
        }

        return $encoded;
    }

    protected function wrapText(string $text, int $maxChars, int $maxLines): string
    {
        $text = trim(preg_replace('/\s+/u', ' ', $text) ?? '');

        if ($text === '') {
            return '';
        }

        $lines = [];
        while ($text !== '' && count($lines) < $maxLines) {
            if (mb_strlen($text) <= $maxChars) {
                $lines[] = $text;
                break;
            }

            $chunk = mb_substr($text, 0, $maxChars);
            $lines[] = $chunk;
            $text = ltrim(mb_substr($text, $maxChars));
        }

        if ($text !== '' && $lines !== []) {
            $last = $lines[array_key_last($lines)];
            $lines[array_key_last($lines)] = mb_substr($last, 0, max(1, $maxChars - 1)).'…';
        }

        return implode("\n", $lines);
    }

    protected function fontFile(): ?string
    {
        $configured = config('larablog.cover_font');
        $candidates = array_filter([
            is_string($configured) && $configured !== '' ? $configured : null,
            resource_path('fonts/Cover.ttf'),
            resource_path('fonts/NotoSansSC-Regular.otf'),
            '/System/Library/Fonts/Supplemental/Arial Unicode.ttf',
            '/Library/Fonts/Arial Unicode.ttf',
            '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
            '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc',
            '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
        ]);

        foreach ($candidates as $path) {
            if (is_string($path) && is_file($path)) {
                return $path;
            }
        }

        return null;
    }
}
