<?php

namespace App\Services;

use App\Enums\FeatureEnum;
use App\Exceptions\ApiHttpException;
use App\Models\Archive;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class ArchivesService
{
    public function getArchives(array $params, User $user = null)
    {
        $itemsPerPage = $params['itemsPerPage'] ?? 9;
        $page = $params['page'] ?? 1;
        $availableYears = $this->getAvailableYears($user);
        $year = $params['year'] ?? ($availableYears[0] ?? null);
        $sort = $params['sort'] ?? 'desc';

        // Check if user is logged in and has access to archives
        if (!$user) {
            throw new ApiHttpException(401, 'access_denied');
        }

        $hasFullArchive = $user->hasFeature(FeatureEnum::FULL_ARCHIVE);
        $hasBasicArchive = $user->hasFeature(FeatureEnum::BASIC_ARCHIVE);

        if (!$hasFullArchive && !$hasBasicArchive) {
            throw new ApiHttpException(403, 'access_denied');
        }

        $query = Archive::full()
            ->with(['document', 'image'])
            ->where('status', 'published');

        // Apply date restriction for basic archive users
        if (!$hasFullArchive && $hasBasicArchive) {
            $subscriptionStartDate = $this->getUserSubscriptionStartDate($user);
            if ($subscriptionStartDate) {
                $query->where('archive_date', '>=', $subscriptionStartDate);
            }
        }

        // Filter by specific year if provided
        if ($year) {
            $query->whereYear('archive_date', $year);
        }

        // Sort by latest or oldest
        $query->orderBy('archive_date', $sort)
            ->orderBy('archives.id', $sort);

        return $query->paginate($itemsPerPage, ['*'], 'page', $page);
    }

    public function getArchiveBySlug(string $slug, User $user = null)
    {
        $archive = Archive::full()
            ->with([
                'document',
                'image',
                'archiveAccordions' => function ($query) {
                    $query->full()
                        ->with([
                            'links' => function ($query) {
                                $query->full()
                                    ->orderBy('position');
                            }
                        ])
                        ->orderBy('position');
                },
            ])
            ->where('slug', $slug)
            ->where('status', 'published')
            ->first();


        if (!$archive) {
            return null;
        }

        // Check user has archive access
        if (!$user) {
            throw new ApiHttpException(401, 'access_denied');
        }

        $hasFullArchive = $user->hasFeature(FeatureEnum::FULL_ARCHIVE);
        $hasBasicArchive = $user->hasFeature(FeatureEnum::BASIC_ARCHIVE);

        if (!$hasFullArchive && !$hasBasicArchive) {
            throw new ApiHttpException(403, 'access_denied');
        }

        // Check date restriction for basic archive users
        if (!$hasFullArchive && $hasBasicArchive) {
            $subscriptionStartDate = $this->getUserSubscriptionStartDate($user);

            if ($subscriptionStartDate && $archive->archive_date < $subscriptionStartDate) {
                throw new ApiHttpException(403, 'access_denied');
            }
        }

        return $archive;
    }

    public function getAvailableYears(User $user = null): array
    {
        if (!$user) {
            return [];
        }

        $hasFullArchive = $user->hasFeature(FeatureEnum::FULL_ARCHIVE);
        $hasBasicArchive = $user->hasFeature(FeatureEnum::BASIC_ARCHIVE);

        if (!$hasFullArchive && !$hasBasicArchive) {
            return [];
        }

        $query = Archive::full()
            ->where('status', 'published')
            ->selectRaw('DISTINCT YEAR(archive_date) as year');

        // Apply date restriction for basic archive users
        if (!$hasFullArchive && $hasBasicArchive) {
            $subscriptionStartDate = $this->getUserSubscriptionStartDate($user);
            if ($subscriptionStartDate) {
                $query->where('archive_date', '>=', $subscriptionStartDate);
            }
        }

        return $query->orderBy('year', 'desc')
            ->pluck('year')
            ->toArray();
    }

    private function getUserSubscriptionStartDate(User $user): ?string
    {
        $subscription = DB::table('account_members')
            ->join('accounts', 'account_members.account_id', '=', 'accounts.id')
            ->join('subscriptions', 'accounts.id', '=', 'subscriptions.account_id')
            ->where('account_members.user_id', $user->id)
            ->where('account_members.status', 'accepted')
            ->where('subscriptions.status', Subscription::STATUS_ACTIVE)
            ->select('subscriptions.start_date')
            ->first();

        if (!$subscription) {
            return null;
        }

        return $subscription->start_date;
    }

    public function downloadDocument(string $slug, ?User $user)
    {
        $archive = $this->getArchiveBySlug($slug, $user);

        if (!$archive) {
            throw new ApiHttpException(404, 'item_not_found');
        }

        $document = $archive->document;

        if (!$document) {
            throw new ApiHttpException(404, 'document_not_found');
        }

        $disk = $document->base_folder;
        $filePath = $document->path;

        if (!Storage::disk($disk)->exists($filePath)) {
            throw new ApiHttpException(404, 'document_not_found');
        }

        $filename = $document->original_filename;

        return response()->streamDownload(function () use ($disk, $filePath) {
            readfile(Storage::disk($disk)->path($filePath));
        }, $filename, [
            'Content-Type' => 'application/octet-stream',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ]);
    }
}
