<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Announcement;
use App\Models\AnnouncementAttachment;
use App\Notifications\AnnouncementPublishedNotification;
use App\Services\HrmsNotificationService;
use App\Support\FormTextRules;
use App\Support\ResolvesPrivateUploads;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

class AnnouncementController extends Controller
{
    use ResolvesPrivateUploads;

    public function __construct(
        protected HrmsNotificationService $notifier
    ) {}

    private function ensureTenantAccess(Announcement $announcement): void
    {
        $companyId = Auth::user()?->company_id;
        if ($companyId && (int) $announcement->company_id !== (int) $companyId) {
            abort(403);
        }
    }

    public function index()
    {
        $companyId = Auth::user()?->company_id;

        $base = Announcement::query();
        if ($companyId) {
            $base->where('company_id', $companyId);
        }

        $monthStart = now()->startOfMonth();

        $kpis = [
            'total' => (clone $base)->count(),
            'active' => (clone $base)->where('is_active', true)->count(),
            'inactive' => (clone $base)->where('is_active', false)->count(),
            'pinned' => (clone $base)->where('is_pinned', true)->count(),
            'this_month' => (clone $base)->where('created_at', '>=', $monthStart)->count(),
        ];

        $announcements = (clone $base)
            ->with(['creator', 'attachments'])
            ->withCount('attachments')
            ->orderByDesc('is_pinned')
            ->orderByDesc('created_at')
            ->paginate(15);

        return view('announcements.index', compact('announcements', 'kpis'));
    }

    public function create()
    {
        return view('announcements.create');
    }

    public function store(Request $request)
    {
        $companyId = Auth::user()?->company_id;
        $validated = $request->validate([
            'title' => FormTextRules::notNumericOnly(true, 191),
            'body' => FormTextRules::notNumericOnlyHtml(false, 50000),
            'is_pinned' => 'boolean',
            'is_active' => 'required|boolean',
            'attachments' => 'nullable|array|max:10',
            'attachments.*' => 'file|max:20480|mimes:jpg,jpeg,png,gif,webp,pdf,doc,docx,xls,xlsx,ppt,pptx,txt,csv',
        ], FormTextRules::messages());
        $validated['is_pinned'] = $request->boolean('is_pinned');
        $validated['is_active'] = $request->boolean('is_active');
        $validated['created_by'] = Auth::id();
        $validated['company_id'] = $companyId;
        $uploadedFiles = $request->file('attachments', []);

        $announcement = null;
        DB::transaction(function () use ($validated, $uploadedFiles, $companyId, &$announcement): void {
            $announcement = Announcement::create($validated);

            foreach ($uploadedFiles as $file) {
                $path = $file->store('announcements/' . ($companyId ?? 'shared'), $this->privateUploadDisk());
                $announcement->attachments()->create([
                    'company_id' => $companyId,
                    'path' => $path,
                    'original_name' => $file->getClientOriginalName(),
                    'mime_type' => $file->getClientMimeType(),
                    'size_bytes' => $file->getSize(),
                ]);
            }
        });

        if ($announcement && $announcement->is_active && $companyId) {
            $this->notifier->notifyActiveCompanyUsers(
                (int) $companyId,
                new AnnouncementPublishedNotification($announcement),
                [(int) Auth::id()]
            );
        }

        return redirect()->route('announcements.index')->with('success', 'Announcement created successfully.');
    }

    public function edit(Announcement $announcement)
    {
        $this->ensureTenantAccess($announcement);
        $announcement->load('attachments');
        return view('announcements.edit', compact('announcement'));
    }

    public function update(Request $request, Announcement $announcement)
    {
        $this->ensureTenantAccess($announcement);
        $companyId = Auth::user()?->company_id;
        $validated = $request->validate([
            'title' => FormTextRules::notNumericOnly(true, 191),
            'body' => FormTextRules::notNumericOnlyHtml(false, 50000),
            'is_pinned' => 'boolean',
            'is_active' => 'required|boolean',
            'attachments' => 'nullable|array|max:10',
            'attachments.*' => 'file|max:20480|mimes:jpg,jpeg,png,gif,webp,pdf,doc,docx,xls,xlsx,ppt,pptx,txt,csv',
        ], FormTextRules::messages());

        $validated['is_pinned'] = $request->boolean('is_pinned');
        $validated['is_active'] = $request->boolean('is_active');
        $uploadedFiles = $request->file('attachments', []);

        $wasActive = $announcement->is_active;

        DB::transaction(function () use ($announcement, $validated, $uploadedFiles, $companyId): void {
            $announcement->update($validated);

            foreach ($uploadedFiles as $file) {
                $path = $file->store('announcements/' . ($companyId ?? 'shared'), $this->privateUploadDisk());
                $announcement->attachments()->create([
                    'company_id' => $companyId,
                    'path' => $path,
                    'original_name' => $file->getClientOriginalName(),
                    'mime_type' => $file->getClientMimeType(),
                    'size_bytes' => $file->getSize(),
                ]);
            }
        });

        if (! $wasActive && $announcement->fresh()->is_active && $companyId) {
            $this->notifier->notifyActiveCompanyUsers(
                (int) $companyId,
                new AnnouncementPublishedNotification($announcement->fresh()),
                [(int) Auth::id()]
            );
        }

        return redirect()->route('announcements.index')->with('success', 'Announcement updated successfully.');
    }

    public function downloadAttachment(AnnouncementAttachment $attachment): BinaryFileResponse
    {
        $attachment->loadMissing('announcement');
        abort_unless($attachment->announcement, 404);
        $this->ensureTenantAccess($attachment->announcement);

        $companyId = Auth::user()?->company_id;
        if ($companyId && (int) $attachment->company_id !== (int) $companyId) {
            abort(403);
        }

        abort_if(! $this->privateUploadExists($attachment->path), 404);

        return response()->download(
            $this->privateUploadAbsolutePath($attachment->path),
            $attachment->original_name ?: basename($attachment->path)
        );
    }
}
