<?php

declare(strict_types=1);

namespace App\Application\Admin;

use App\Domain\PreSave\PreSaveCampaign;
use App\Domain\PreSave\PreSaveCampaignRepository;
use App\Domain\PreSave\PreSaveRegistrationRepository;
use App\Domain\PreSave\ValueObjects\CampaignStatus;
use App\Framework\Attributes\Auth;
use App\Framework\Attributes\Route;
use App\Framework\Core\Method;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\FrameworkException;
use App\Framework\Http\HttpRequest;
use App\Framework\Http\JsonResult;
use App\Framework\Http\Redirect;
use App\Framework\Http\ViewResult;

/**
 * Admin Controller for Pre-Save Campaign Management
 */
#[Auth(strategy: 'ip', allowedIps: ['127.0.0.1', '::1'])]
final readonly class PreSaveCampaignController
{
    public function __construct(
        private PreSaveCampaignRepository $campaignRepository,
        private PreSaveRegistrationRepository $registrationRepository
    ) {
    }

    /**
     * Show all campaigns overview
     */
    #[Route(path: '/admin/presave/campaigns', method: Method::GET)]
    public function index(HttpRequest $request): ViewResult
    {
        $campaigns = $this->campaignRepository->findAll();

        return new ViewResult('admin/presave/campaigns/index', [
            'campaigns' => $campaigns,
            'stats' => $this->getGlobalStats(),
        ]);
    }

    /**
     * Show create campaign form
     */
    #[Route(path: '/admin/presave/campaigns/create', method: Method::GET)]
    public function create(): ViewResult
    {
        return new ViewResult('admin/presave/campaigns/create');
    }

    /**
     * Store new campaign
     */
    #[Route(path: '/admin/presave/campaigns', method: Method::POST)]
    public function store(HttpRequest $request): Redirect
    {
        $data = $request->parsedBody->toArray();

        // Validate required fields
        $this->validateCampaignData($data);

        // Parse track URLs from form
        $trackUrls = [];
        if (! empty($data['spotify_url'])) {
            $trackUrls['spotify'] = $data['spotify_url'];
        }
        if (! empty($data['apple_music_url'])) {
            $trackUrls['apple_music'] = $data['apple_music_url'];
        }
        if (! empty($data['tidal_url'])) {
            $trackUrls['tidal'] = $data['tidal_url'];
        }

        // Create campaign
        $campaign = PreSaveCampaign::create(
            title: $data['title'],
            artistName: $data['artist_name'],
            coverImageUrl: $data['cover_image_url'],
            description: $data['description'] ?? null,
            releaseDate: strtotime($data['release_date']),
            trackUrls: $trackUrls,
            startDate: ! empty($data['start_date']) ? strtotime($data['start_date']) : null
        );

        $this->campaignRepository->save($campaign);

        return Redirect::to('/admin/presave/campaigns')
            ->withFlashMessage('success', 'Campaign created successfully!');
    }

    /**
     * Show campaign details with registrations
     */
    #[Route(path: '/admin/presave/campaigns/{id}', method: Method::GET)]
    public function show(HttpRequest $request): ViewResult
    {
        $campaignId = $request->routeParams->get('id');
        $campaign = $this->campaignRepository->findById($campaignId);

        if ($campaign === null) {
            throw FrameworkException::create(
                ErrorCode::ENTITY_NOT_FOUND,
                "Campaign with ID {$campaignId} not found"
            );
        }

        $registrations = $this->registrationRepository->findByCampaign($campaignId);
        $stats = $this->getCampaignStats($campaign, $registrations);

        return new ViewResult('admin/presave/campaigns/show', [
            'campaign' => $campaign,
            'registrations' => $registrations,
            'stats' => $stats,
        ]);
    }

    /**
     * Show edit campaign form
     */
    #[Route(path: '/admin/presave/campaigns/{id}/edit', method: Method::GET)]
    public function edit(HttpRequest $request): ViewResult
    {
        $campaignId = $request->routeParams->get('id');
        $campaign = $this->campaignRepository->findById($campaignId);

        if ($campaign === null) {
            throw FrameworkException::create(
                ErrorCode::ENTITY_NOT_FOUND,
                "Campaign with ID {$campaignId} not found"
            );
        }

        return new ViewResult('admin/presave/campaigns/edit', [
            'campaign' => $campaign,
        ]);
    }

    /**
     * Update campaign
     */
    #[Route(path: '/admin/presave/campaigns/{id}', method: Method::PUT)]
    public function update(HttpRequest $request): Redirect
    {
        $campaignId = $request->routeParams->get('id');
        $campaign = $this->campaignRepository->findById($campaignId);

        if ($campaign === null) {
            throw FrameworkException::create(
                ErrorCode::ENTITY_NOT_FOUND,
                "Campaign with ID {$campaignId} not found"
            );
        }

        $data = $request->parsedBody->toArray();
        $this->validateCampaignData($data);

        // Parse track URLs
        $trackUrls = [];
        if (! empty($data['spotify_url'])) {
            $trackUrls['spotify'] = $data['spotify_url'];
        }
        if (! empty($data['apple_music_url'])) {
            $trackUrls['apple_music'] = $data['apple_music_url'];
        }
        if (! empty($data['tidal_url'])) {
            $trackUrls['tidal'] = $data['tidal_url'];
        }

        // Update campaign
        $updatedCampaign = $campaign->updateDetails(
            title: $data['title'],
            artistName: $data['artist_name'],
            coverImageUrl: $data['cover_image_url'],
            description: $data['description'] ?? null,
            releaseDate: strtotime($data['release_date']),
            trackUrls: $trackUrls
        );

        $this->campaignRepository->save($updatedCampaign);

        return Redirect::to("/admin/presave/campaigns/{$campaignId}")
            ->withFlashMessage('success', 'Campaign updated successfully!');
    }

    /**
     * Delete campaign
     */
    #[Route(path: '/admin/presave/campaigns/{id}', method: Method::DELETE)]
    public function destroy(HttpRequest $request): JsonResult
    {
        $campaignId = $request->routeParams->get('id');
        $campaign = $this->campaignRepository->findById($campaignId);

        if ($campaign === null) {
            return new JsonResult([
                'success' => false,
                'message' => 'Campaign not found',
            ], 404);
        }

        $this->campaignRepository->delete($campaignId);

        return new JsonResult([
            'success' => true,
            'message' => 'Campaign deleted successfully',
        ]);
    }

    /**
     * Activate campaign
     */
    #[Route(path: '/admin/presave/campaigns/{id}/activate', method: Method::POST)]
    public function activate(HttpRequest $request): Redirect
    {
        $campaignId = $request->routeParams->get('id');
        $campaign = $this->campaignRepository->findById($campaignId);

        if ($campaign === null) {
            throw FrameworkException::create(
                ErrorCode::ENTITY_NOT_FOUND,
                "Campaign with ID {$campaignId} not found"
            );
        }

        $activeCampaign = $campaign->updateStatus(CampaignStatus::ACTIVE);
        $this->campaignRepository->save($activeCampaign);

        return Redirect::to("/admin/presave/campaigns/{$campaignId}")
            ->withFlashMessage('success', 'Campaign activated successfully!');
    }

    /**
     * Pause campaign
     */
    #[Route(path: '/admin/presave/campaigns/{id}/pause', method: Method::POST)]
    public function pause(HttpRequest $request): Redirect
    {
        $campaignId = $request->routeParams->get('id');
        $campaign = $this->campaignRepository->findById($campaignId);

        if ($campaign === null) {
            throw FrameworkException::create(
                ErrorCode::ENTITY_NOT_FOUND,
                "Campaign with ID {$campaignId} not found"
            );
        }

        $pausedCampaign = $campaign->updateStatus(CampaignStatus::PAUSED);
        $this->campaignRepository->save($pausedCampaign);

        return Redirect::to("/admin/presave/campaigns/{$campaignId}")
            ->withFlashMessage('success', 'Campaign paused successfully!');
    }

    /**
     * Complete campaign
     */
    #[Route(path: '/admin/presave/campaigns/{id}/complete', method: Method::POST)]
    public function complete(HttpRequest $request): Redirect
    {
        $campaignId = $request->routeParams->get('id');
        $campaign = $this->campaignRepository->findById($campaignId);

        if ($campaign === null) {
            throw FrameworkException::create(
                ErrorCode::ENTITY_NOT_FOUND,
                "Campaign with ID {$campaignId} not found"
            );
        }

        $completedCampaign = $campaign->updateStatus(CampaignStatus::COMPLETED);
        $this->campaignRepository->save($completedCampaign);

        return Redirect::to("/admin/presave/campaigns/{$campaignId}")
            ->withFlashMessage('success', 'Campaign marked as completed!');
    }

    /**
     * Validate campaign data
     */
    private function validateCampaignData(array $data): void
    {
        $required = ['title', 'artist_name', 'cover_image_url', 'release_date'];

        foreach ($required as $field) {
            if (empty($data[$field])) {
                throw FrameworkException::create(
                    ErrorCode::VAL_REQUIRED_FIELD_MISSING,
                    "Field '{$field}' is required"
                )->withData(['field' => $field]);
            }
        }

        // Validate at least one track URL
        if (empty($data['spotify_url']) && empty($data['apple_music_url']) && empty($data['tidal_url'])) {
            throw FrameworkException::create(
                ErrorCode::VAL_BUSINESS_RULE_VIOLATION,
                'At least one track URL (Spotify, Apple Music, or Tidal) is required'
            );
        }
    }

    /**
     * Get global campaign statistics
     */
    private function getGlobalStats(): array
    {
        $allCampaigns = $this->campaignRepository->findAll();

        $stats = [
            'total' => count($allCampaigns),
            'draft' => 0,
            'active' => 0,
            'paused' => 0,
            'completed' => 0,
            'total_registrations' => 0,
        ];

        foreach ($allCampaigns as $campaign) {
            $stats[strtolower($campaign->status->value)]++;

            $registrations = $this->registrationRepository->findByCampaign($campaign->id);
            $stats['total_registrations'] += count($registrations);
        }

        return $stats;
    }

    /**
     * Get campaign-specific statistics
     */
    private function getCampaignStats(PreSaveCampaign $campaign, array $registrations): array
    {
        $stats = [
            'total_registrations' => count($registrations),
            'pending' => 0,
            'processing' => 0,
            'completed' => 0,
            'failed' => 0,
            'by_platform' => [
                'spotify' => 0,
                'apple_music' => 0,
                'tidal' => 0,
            ],
        ];

        foreach ($registrations as $registration) {
            $stats[strtolower($registration->status->value)]++;
            $stats['by_platform'][strtolower($registration->platform->value)]++;
        }

        return $stats;
    }
}
