<?php

declare(strict_types=1);

namespace App\Framework\Notification\Media;

use App\Framework\Notification\Interfaces\{
    SupportsPhotoAttachments,
    SupportsVideoAttachments,
    SupportsAudioAttachments,
    SupportsDocumentAttachments,
    SupportsLocationSharing
};
use App\Framework\Notification\Notification;
use App\Framework\Notification\ValueObjects\NotificationChannel;

/**
 * Central Media Manager
 *
 * Manages media drivers and provides unified API for sending media
 * Uses instanceof to detect driver capabilities
 */
final class MediaManager
{
    /** @var array<string, MediaDriver> */
    private array $drivers = [];

    /**
     * Register a media driver for a channel
     */
    public function registerDriver(NotificationChannel $channel, MediaDriver $driver): void
    {
        $this->drivers[$channel->value] = $driver;
    }

    /**
     * Get driver for channel
     *
     * @throws \RuntimeException if driver not registered
     */
    public function getDriver(NotificationChannel $channel): MediaDriver
    {
        if (!isset($this->drivers[$channel->value])) {
            throw new \RuntimeException("No media driver registered for channel: {$channel->value}");
        }

        return $this->drivers[$channel->value];
    }

    /**
     * Check if channel has a registered driver
     */
    public function hasDriver(NotificationChannel $channel): bool
    {
        return isset($this->drivers[$channel->value]);
    }

    // ==================== Capability Checks ====================

    /**
     * Check if channel supports photo attachments
     */
    public function supportsPhoto(NotificationChannel $channel): bool
    {
        if (!$this->hasDriver($channel)) {
            return false;
        }

        return $this->getDriver($channel) instanceof SupportsPhotoAttachments;
    }

    /**
     * Check if channel supports video attachments
     */
    public function supportsVideo(NotificationChannel $channel): bool
    {
        if (!$this->hasDriver($channel)) {
            return false;
        }

        return $this->getDriver($channel) instanceof SupportsVideoAttachments;
    }

    /**
     * Check if channel supports audio attachments
     */
    public function supportsAudio(NotificationChannel $channel): bool
    {
        if (!$this->hasDriver($channel)) {
            return false;
        }

        return $this->getDriver($channel) instanceof SupportsAudioAttachments;
    }

    /**
     * Check if channel supports document attachments
     */
    public function supportsDocument(NotificationChannel $channel): bool
    {
        if (!$this->hasDriver($channel)) {
            return false;
        }

        return $this->getDriver($channel) instanceof SupportsDocumentAttachments;
    }

    /**
     * Check if channel supports location sharing
     */
    public function supportsLocation(NotificationChannel $channel): bool
    {
        if (!$this->hasDriver($channel)) {
            return false;
        }

        return $this->getDriver($channel) instanceof SupportsLocationSharing;
    }

    // ==================== Send Methods ====================

    /**
     * Send photo
     *
     * @throws \RuntimeException if channel doesn't support photos
     */
    public function sendPhoto(
        NotificationChannel $channel,
        Notification $notification,
        string $photoPath,
        ?string $caption = null
    ): void {
        $driver = $this->getDriver($channel);

        if (!$driver instanceof SupportsPhotoAttachments) {
            throw new \RuntimeException("Channel {$channel->value} does not support photo attachments");
        }

        $driver->sendWithPhoto($notification, $photoPath, $caption);
    }

    /**
     * Send video
     *
     * @throws \RuntimeException if channel doesn't support videos
     */
    public function sendVideo(
        NotificationChannel $channel,
        Notification $notification,
        string $videoPath,
        ?string $caption = null,
        ?string $thumbnailPath = null
    ): void {
        $driver = $this->getDriver($channel);

        if (!$driver instanceof SupportsVideoAttachments) {
            throw new \RuntimeException("Channel {$channel->value} does not support video attachments");
        }

        $driver->sendWithVideo($notification, $videoPath, $caption, $thumbnailPath);
    }

    /**
     * Send audio
     *
     * @throws \RuntimeException if channel doesn't support audio
     */
    public function sendAudio(
        NotificationChannel $channel,
        Notification $notification,
        string $audioPath,
        ?string $caption = null,
        ?int $duration = null
    ): void {
        $driver = $this->getDriver($channel);

        if (!$driver instanceof SupportsAudioAttachments) {
            throw new \RuntimeException("Channel {$channel->value} does not support audio attachments");
        }

        $driver->sendWithAudio($notification, $audioPath, $caption, $duration);
    }

    /**
     * Send document
     *
     * @throws \RuntimeException if channel doesn't support documents
     */
    public function sendDocument(
        NotificationChannel $channel,
        Notification $notification,
        string $documentPath,
        ?string $caption = null,
        ?string $filename = null
    ): void {
        $driver = $this->getDriver($channel);

        if (!$driver instanceof SupportsDocumentAttachments) {
            throw new \RuntimeException("Channel {$channel->value} does not support document attachments");
        }

        $driver->sendWithDocument($notification, $documentPath, $caption, $filename);
    }

    /**
     * Send location
     *
     * @throws \RuntimeException if channel doesn't support location
     */
    public function sendLocation(
        NotificationChannel $channel,
        Notification $notification,
        float $latitude,
        float $longitude,
        ?string $title = null,
        ?string $address = null
    ): void {
        $driver = $this->getDriver($channel);

        if (!$driver instanceof SupportsLocationSharing) {
            throw new \RuntimeException("Channel {$channel->value} does not support location sharing");
        }

        $driver->sendWithLocation($notification, $latitude, $longitude, $title, $address);
    }

    /**
     * Get capabilities summary for a channel
     */
    public function getCapabilities(NotificationChannel $channel): MediaCapabilities
    {
        if (!$this->hasDriver($channel)) {
            return MediaCapabilities::none();
        }

        return new MediaCapabilities(
            supportsPhoto: $this->supportsPhoto($channel),
            supportsVideo: $this->supportsVideo($channel),
            supportsAudio: $this->supportsAudio($channel),
            supportsDocument: $this->supportsDocument($channel),
            supportsLocation: $this->supportsLocation($channel)
        );
    }
}
