<?php

namespace App\Http\Controllers;

use App\Enums\CampaignStatus;
use App\Http\Requests\Campaign\StoreCampaignRequest;
use App\Http\Requests\Campaign\UpdateCampaignRequest;
use App\Models\Ad;
use App\Models\AdPlatform;
use App\Models\Kategori;
use App\Models\User;
use App\Services\CampaignService;
use App\Services\VerificationService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

class CampaignController extends Controller
{
    public function __construct(
        private readonly CampaignService $campaignService,
        private readonly VerificationService $verificationService,
    ) {}

    /**
     * Daftar campaign (FR-CAMP-07). Admin lihat semua, member lihat miliknya.
     * Draft tidak tampil di list utama — ada halaman Drafts terpisah.
     */
    public function index(Request $request): Response
    {
        $user = $request->user();

        $campaigns = Ad::with(['kategoris', 'user', 'adPlatform'])
            ->where('status', '!=', CampaignStatus::Draft)
            ->when(! $user->isAdmin(), fn ($q) => $q->where('user_id', $user->id))
            ->when($request->string('search')->toString(), fn ($q, $search) => $q
                ->where('judul', 'like', "%{$search}%"))
            ->latest()
            ->paginate(15)
            ->withQueryString();

        return Inertia::render('campaigns/Index', [
            'campaigns' => $campaigns,
            'filters' => $request->only(['search']),
        ]);
    }

    public function create(): Response
    {
        return Inertia::render('campaigns/Create', [
            'kategoris' => Kategori::where('status', true)->get(['id', 'nama_kategori']),
            'isAdmin' => request()->user()->isAdmin(),
            'defaultRate' => (int) config('ads.default_rate', 100),
            'adPlatforms' => AdPlatform::orderBy('ad_type')->orderBy('sort_order')->get(['id', 'name', 'slug', 'ad_type', 'countries', 'is_active']),
        ]);
    }

    public function store(StoreCampaignRequest $request): RedirectResponse
    {
        $data = $request->validated();
        $user = $request->user();

        // Admin dapat membuat campaign untuk user lain; member hanya untuk dirinya.
        $owner = $user->isAdmin() && isset($data['user_id'])
            ? User::findOrFail($data['user_id'])
            : $user;

        try {
            $ad = $this->campaignService->create($owner, $data);
        } catch (\DomainException $e) {
            return back()->with('error', $e->getMessage());
        }

        // Generate kode verifikasi untuk iklan link_website.
        if ($ad->needsVerification()) {
            $this->verificationService->generateCode($ad);
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign dibuat, menunggu approve admin.')]);

        return to_route('campaigns.index');
    }

    /**
     * Detail campaign (FR-CAMP-14).
     */
    public function show(Ad $campaign): Response|RedirectResponse
    {
        if (Gate::denies('view-campaign', $campaign)) {
            return to_route('campaigns.index')
                ->with('error', 'Anda tidak memiliki akses ke campaign ini.');
        }

        return Inertia::render('campaigns/Show', [
            'campaign' => $campaign->load(['kategoris', 'user', 'adPlatform']),
            'defaultRate' => (int) config('ads.default_rate', 100),
        ]);
    }

    public function edit(Ad $campaign): Response|RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')
                ->with('error', 'Anda tidak memiliki akses ke campaign ini.');
        }

        // Member hanya bisa edit campaign Pending/Draft/Aktif-di-pause; admin bisa edit semua status.
        if (! request()->user()->isAdmin() && ! ($campaign->status->isPending() || $campaign->status->isDraft() || $campaign->isPausedActive())) {
            return to_route('campaigns.index')
                ->with('error', 'Campaign hanya dapat diubah saat berstatus Pending, Draft, atau Aktif yang dihentikan (Stop).');
        }

        return Inertia::render('campaigns/Edit', [
            'campaign' => $campaign->load(['kategoris', 'adPlatform']),
            'isAdmin' => request()->user()->isAdmin(),
            'defaultRate' => (int) config('ads.default_rate', 100),
            'kategoris' => Kategori::where('status', true)->get(['id', 'nama_kategori']),
            'adPlatforms' => AdPlatform::orderBy('ad_type')->orderBy('sort_order')->get(['id', 'name', 'slug', 'ad_type', 'countries', 'is_active']),
        ]);
    }

    /**
     * Verifikasi situs tujuan (untuk iklan link_website).
     */
    public function verify(Ad $campaign): RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')->with('error', 'Anda tidak memiliki akses.');
        }

        if (! $campaign->needsVerification()) {
            return to_route('campaigns.index')->with('error', 'Campaign ini tidak memerlukan verifikasi.');
        }

        $verified = $this->verificationService->verify($campaign);

        if ($verified) {
            Inertia::flash('toast', ['type' => 'success', 'message' => __('Situs berhasil diverifikasi!')]);
        } else {
            Inertia::flash('toast', ['type' => 'error', 'message' => __('Verifikasi gagal. Pastikan kode verifikasi sudah dipasang di situs Anda.')]);
        }

        return to_route('campaigns.show', $campaign);
    }

    public function update(UpdateCampaignRequest $request, Ad $campaign): RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')
                ->with('error', 'Anda tidak memiliki akses ke campaign ini.');
        }

        // Member hanya bisa edit campaign Pending/Draft/Aktif-di-pause; admin bisa edit semua status.
        if (! $request->user()->isAdmin() && ! ($campaign->status->isPending() || $campaign->status->isDraft() || $campaign->isPausedActive())) {
            return to_route('campaigns.index')
                ->with('error', 'Campaign hanya dapat diubah saat berstatus Pending, Draft, atau Aktif yang dihentikan (Stop).');
        }

        $campaign->update($request->validated());

        // Sync kategori (many-to-many) bila ada di payload.
        if ($request->has('kategori_ids')) {
            $campaign->kategoris()->sync($request->validated()['kategori_ids'] ?? []);
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign diperbarui.')]);

        return to_route('campaigns.index');
    }

    /**
     * Approve campaign pending → Aktif (FR-CAMP-05). Admin only.
     */
    public function approve(Ad $campaign): RedirectResponse
    {
        if (! request()->user()->isAdmin()) {
            return to_route('campaigns.index')->with('error', 'Hanya admin yang dapat menyetujui campaign.');
        }

        try {
            $this->campaignService->approve($campaign);
        } catch (\DomainException $e) {
            return back()->with('error', $e->getMessage());
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign disetujui & aktif.')]);

        return to_route('campaigns.index');
    }

    /**
     * Jadikan campaign Draft (FR-CAMP-06): simpan tanpa tayang, credit terkunci.
     * Member hanya miliknya; admin semua.
     */
    public function draft(Ad $campaign): RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')->with('error', 'Anda tidak memiliki akses ke campaign ini.');
        }

        try {
            $this->campaignService->toDraft($campaign);
        } catch (\DomainException $e) {
            return back()->with('error', $e->getMessage());
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign disimpan sebagai draft.')]);

        return to_route('campaigns.index');
    }

    /**
     * Restore campaign Draft → langsung Aktif.
     * Member hanya miliknya; admin semua.
     */
    public function restore(Ad $campaign): RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')->with('error', 'Anda tidak memiliki akses ke campaign ini.');
        }

        try {
            $this->campaignService->restore($campaign);
        } catch (\DomainException $e) {
            return back()->with('error', $e->getMessage());
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign diaktifkan kembali.')]);

        return to_route('campaigns.index');
    }

    /**
     * Daftar campaign Draft (FR-CAMP-07). Admin lihat semua, member miliknya.
     */
    public function drafts(Request $request): Response
    {
        $user = $request->user();

        $campaigns = Ad::with(['kategoris', 'user'])
            ->where('status', CampaignStatus::Draft)
            ->when(! $user->isAdmin(), fn ($q) => $q->where('user_id', $user->id))
            ->when($request->string('search')->toString(), fn ($q, $search) => $q
                ->where('judul', 'like', "%{$search}%"))
            ->latest()
            ->paginate(15)
            ->withQueryString();

        return Inertia::render('campaigns/Drafts', [
            'campaigns' => $campaigns,
            'filters' => $request->only(['search']),
        ]);
    }

    /**
     * Stop (pause) campaign Aktif: berhenti tayang tanpa refund credit.
     * Pemilik + admin.
     */
    public function stop(Ad $campaign): RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')->with('error', 'Anda tidak memiliki akses ke campaign ini.');
        }

        try {
            $this->campaignService->pause($campaign);
        } catch (\DomainException $e) {
            return back()->with('error', $e->getMessage());
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign dihentikan (pause).')]);

        return to_route('campaigns.index');
    }

    /**
     * Start (resume) campaign yang di-pause: kembali tayang.
     * Pemilik + admin.
     */
    public function start(Ad $campaign): RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')->with('error', 'Anda tidak memiliki akses ke campaign ini.');
        }

        try {
            $this->campaignService->resume($campaign);
        } catch (\DomainException $e) {
            return back()->with('error', $e->getMessage());
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign dimulai kembali.')]);

        return to_route('campaigns.index');
    }

    public function destroy(Ad $campaign): RedirectResponse
    {
        if (Gate::denies('manage-campaign', $campaign)) {
            return to_route('campaigns.index')->with('error', 'Anda tidak memiliki akses.');
        }

        try {
            $this->campaignService->delete($campaign);
        } catch (\DomainException $e) {
            return back()->with('error', $e->getMessage());
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Campaign dihapus.')]);

        return to_route('campaigns.index');
    }

    /**
     * Ekspor daftar campaign ke CSV (Excel-compatible) — FR-CAMP-09, NFR-10.
     * Member hanya ekspor miliknya; admin semua.
     */
    public function export(Request $request): StreamedResponse
    {
        $user = $request->user();

        $campaigns = Ad::with(['kategoris', 'user'])
            ->when(! $user->isAdmin(), fn ($q) => $q->where('user_id', $user->id))
            ->latest()
            ->get();

        $headers = [
            'Content-Type' => 'text/csv; charset=UTF-8',
            'Content-Disposition' => 'attachment; filename="campaigns-'.now()->format('Y-m-d').'.csv"',
        ];

        $callback = function () use ($campaigns): void {
            $handle = fopen('php://output', 'w');
            // BOM agar Excel membaca UTF-8 dengan benar.
            fwrite($handle, "\xEF\xBB\xBF");
            fputcsv($handle, ['Judul', 'URL', 'Kategori', 'Pemilik', 'Budget Harian', 'Klik Hari Ini', 'Rollover', 'Klik Total', 'Status', 'Dibuat']);

            foreach ($campaigns as $ad) {
                fputcsv($handle, [
                    $ad->judul,
                    $ad->url,
                    $ad->kategoris->pluck('nama_kategori')->join(', '),
                    $ad->user?->name ?? '',
                    $ad->budget_harian ?? 0,
                    $ad->klik_hari_ini ?? 0,
                    $ad->rollover_klik ?? 0,
                    $ad->klik,
                    $ad->status->label(),
                    $ad->created_at->format('Y-m-d H:i'),
                ]);
            }
            fclose($handle);
        };

        return response()->stream($callback, 200, $headers);
    }
}
