<?php

namespace App\Http\Controllers;

use App\Enums\BillingStatus;
use App\Http\Requests\Billing\StoreBillingRequest;
use App\Http\Requests\Billing\UpdateBillingRequest;
use App\Models\Bank;
use App\Models\Billing;
use App\Models\User;
use App\Services\BillingPaymentService;
use App\Services\DuitkuService;
use App\Services\InvoiceService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Inertia\Inertia;
use Inertia\Response;

class BillingController extends Controller
{
    public function __construct(
        private readonly InvoiceService $invoiceService,
        private readonly DuitkuService $duitkuService,
        private readonly BillingPaymentService $billingPaymentService,
    ) {}

    /**
     * Daftar billing (FR-BILL-06). Admin lihat semua, member lihat miliknya.
     */
    public function index(Request $request): Response
    {
        $user = $request->user();

        $billings = Billing::with(['user', 'bank'])
            ->when(! $user->isAdmin(), fn ($q) => $q->where('user_id', $user->id))
            ->when($request->string('search')->toString(), fn ($q, $search) => $q
                ->where('no_invoice', 'like', "%{$search}%"))
            ->latest()
            ->paginate(15)
            ->withQueryString();

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

    public function create(Request $request): Response
    {
        return Inertia::render('billings/Create', [
            'banks' => Bank::where('status', true)->get(['id', 'kode', 'keterangan']),
            'users' => $request->user()->isAdmin()
                ? User::orderBy('name')->get(['id', 'name', 'email'])
                : [],
        ]);
    }

    public function store(StoreBillingRequest $request): RedirectResponse|\Symfony\Component\HttpFoundation\Response
    {
        $data = $request->validated();
        $user = $request->user();

        // Member hanya bisa membuat billing untuk dirinya sendiri; admin pilih user.
        $targetUserId = $user->isAdmin() ? $data['user_id'] : $user->id;

        $billing = Billing::create([
            'no_invoice' => $this->invoiceService->generate(),
            'jumlah_credit' => $data['jumlah_credit'],
            'rate' => $data['rate'],
            'total' => $data['jumlah_credit'] * $data['rate'],
            'bank_id' => $data['bank_id'] ?? null,
            'status' => BillingStatus::Pending,
            'payment_method' => $data['payment_method'] ?? 'manual',
            'user_id' => $targetUserId,
        ]);

        // Metode Duitku: buat invoice di gateway lalu arahkan member ke payment URL.
        if ($billing->isDuitku()) {
            if (! $this->duitkuService->isConfigured()) {
                $billing->delete();

                return back()->with('error', 'Pembayaran Duitku belum tersedia. Silakan pilih transfer manual.');
            }

            try {
                $payment = $this->duitkuService->createPayment($billing->load('user'));
            } catch (\RuntimeException $e) {
                $billing->delete();

                return back()->with('error', $e->getMessage());
            }

            $billing->update([
                'duitku_reference' => $payment['reference'],
                'duitku_payment_url' => $payment['payment_url'],
                'duitku_payment_method' => $payment['payment_method'],
                'duitku_status_code' => $payment['status_code'],
                'duitku_status_message' => $payment['status_message'],
                'duitku_response' => $payment['raw'],
                'duitku_requested_at' => now(),
            ]);

            // Arahkan browser member ke halaman pembayaran Duitku.
            return Inertia::location($payment['payment_url']);
        }

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Invoice :no dibuat, menunggu konfirmasi.', ['no' => $billing->no_invoice])]);

        return to_route('billings.index');
    }

    public function edit(Billing $billing): Response|RedirectResponse
    {
        if (Gate::denies('manage-billing', $billing)) {
            return to_route('billings.index')
                ->with('error', 'Anda tidak memiliki hak akses.');
        }

        if (! $billing->isMutable()) {
            return to_route('billings.index')
                ->with('error', 'Invoice yang sudah Lunas tidak dapat diubah.');
        }

        return Inertia::render('billings/Edit', [
            'billing' => $billing->load(['user', 'bank']),
            'banks' => Bank::where('status', true)->get(['id', 'kode', 'keterangan']),
            'users' => User::orderBy('name')->get(['id', 'name', 'email']),
        ]);
    }

    public function update(UpdateBillingRequest $request, Billing $billing): RedirectResponse
    {
        if (! $billing->isMutable()) {
            Inertia::flash('toast', ['type' => 'error', 'message' => __('Invoice yang sudah Lunas tidak dapat diubah.')]);

            return to_route('billings.index');
        }

        $data = $request->validated();

        $billing->update([
            'jumlah_credit' => $data['jumlah_credit'],
            'rate' => $data['rate'],
            'total' => $data['jumlah_credit'] * $data['rate'],
            'bank_id' => $data['bank_id'] ?? null,
            'user_id' => $data['user_id'],
            'payment_method' => $data['payment_method'] ?? $billing->payment_method,
        ]);

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

        return to_route('billings.index');
    }

    /**
     * Konfirmasi pembayaran manual → status Lunas, saldo credit +N, mutasi In (FR-BILL-04).
     * Idempoten: tidak menambah credit dua kali. Memakai BillingPaymentService
     * (sama jalurnya dengan callback Duitku).
     */
    public function confirm(Billing $billing): RedirectResponse
    {
        if (Gate::denies('manage-billing', $billing)) {
            return to_route('billings.index')
                ->with('error', 'Anda tidak memiliki hak akses.');
        }

        if ($billing->status === BillingStatus::Lunas) {
            Inertia::flash('toast', ['type' => 'info', 'message' => __('Invoice sudah dikonfirmasi sebelumnya.')]);

            return to_route('billings.index');
        }

        if (! $billing->status->isPending()) {
            Inertia::flash('toast', ['type' => 'error', 'message' => __('Hanya invoice Pending yang dapat dikonfirmasi.')]);

            return to_route('billings.index');
        }

        $this->billingPaymentService->markPaid($billing, ['source' => 'manual']);

        Inertia::flash('toast', ['type' => 'success', 'message' => __('Pembayaran dikonfirmasi. +:n credit ditambahkan.', ['n' => $billing->jumlah_credit])]);

        return to_route('billings.index');
    }

    /**
     * Landing kembali dari halaman pembayaran Duitku.
     * Tidak kredit di sini — callback (server-to-server) adalah source-of-truth.
     */
    public function duitkuReturn(Request $request): RedirectResponse
    {
        $merchantOrderId = $request->string('merchantOrderId')->toString();

        if ($merchantOrderId) {
            $billing = Billing::where('no_invoice', $merchantOrderId)->first();
            if ($billing && $billing->status === BillingStatus::Lunas) {
                Inertia::flash('toast', ['type' => 'success', 'message' => __('Pembayaran berhasil. Credit telah ditambahkan.')]);
            } else {
                Inertia::flash('toast', ['type' => 'info', 'message' => __('Pembayaran sedang diproses. Credit akan masuk otomatis setelah konfirmasi.')]);
            }
        } else {
            Inertia::flash('toast', ['type' => 'info', 'message' => __('Pembayaran sedang diproses.')]);
        }

        return to_route('billings.index');
    }

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

        if (! $billing->isMutable()) {
            Inertia::flash('toast', ['type' => 'error', 'message' => __('Invoice yang sudah Lunas tidak dapat dihapus.')]);

            return to_route('billings.index');
        }

        $billing->delete();

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

        return to_route('billings.index');
    }
}
