<?php

namespace App\Http\Controllers\Backoffice;

use App\Facades\AccountsService;
use App\Http\Controllers\Controller;
use App\Facades\Backoffice\BackendUserService;
use App\Http\Requests\AccountMemberAdminStatus;
use App\Http\Requests\AccountMemberInviteRequest;
use App\Http\Requests\BasicListingRequest;
use App\Http\Requests\Backoffice\AccountCreateRequest;
use App\Http\Requests\Backoffice\AccountInvoiceRequest;
use App\Http\Requests\Backoffice\AccountListRequest;
use App\Http\Requests\Backoffice\AccountRequest;
use App\Http\Requests\Backoffice\AddressCreateUpdateRequest;
use App\Http\Requests\Backoffice\SubscriptionCreateUpdateRequest;
use App\Http\Resources\Backoffice\Accounts\AccountDetailResource;
use App\Http\Resources\Backoffice\Accounts\AccountInvoiceResource;
use App\Http\Resources\Backoffice\Accounts\AccountResource;
use App\Http\Resources\Backoffice\Accounts\AddressDetailResource;
use App\Http\Resources\Backoffice\Accounts\SubscriptionDetailResource;
use App\Http\Resources\Subscriptions\MemberResource;
use App\Http\Requests\Backoffice\AdminContentAutoComplete;
use App\Http\Requests\Backoffice\SubscriptionCancelRequest;
use App\Models\Account;
use App\Models\AccountInvoice;
use App\Models\Address;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use Inertia\Inertia;

class AccountsController extends Controller
{
    /* BO Function */
    public function getIndex()
    {
        $loggedUser = BackendUserService::getLoggedUser();

        return Inertia::render('Backoffice/Accounts/ListAccounts', [
            'data' => [
                'user'          => $loggedUser,
            ]
        ]);
    }

    /* BO Function */
    public function postList(AccountListRequest $request)
    {
        $data = $request->validated();

        $loggedUser = BackendUserService::getLoggedUser();

        if (!empty($userId) && $loggedUser->id != $userId
            && !$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $list = AccountsService::getAccountsForAdmin($data);

        return AccountResource::collection($list);
    }

    public function getEdit($accountId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);
        $resource = new AccountResource($account);

        return Inertia::render('Backoffice/Accounts/EditAccount', [
            'data' => $resource,
            'message' => Session::get('message'),
            'errorMessage' => Session::get('errorMessage')
        ]);
    }

    public function getAccount($accountId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);
        $resource = new AccountDetailResource($account);

        return $resource;
    }

    public function updateAccount($accountId, AccountRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $data = $request->validated();

        $account = AccountsService::adminUpdate($account, $data);

        return new AccountDetailResource($account);
    }

    public function getAddress(int $accountId, string $type)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $address = null;
        switch ($type) {
            case 'company':
                $address = $account->address;
                break;
            case 'billing':
                $address = $account->billingAddress;
                break;
            case 'shipping':
                $address = $account->shippingAddress;
                break;
            default:
                abort(404);
        }

        $sameAsCompany = $account->address_id && $type != 'company' && $account->address_id == $address->id ? 1 : 0;

        return new AddressDetailResource($address ?? new Address, $sameAsCompany);
    }

    public function saveAddress(int $accountId, AddressCreateUpdateRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $data = $request->validated();

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $address = AccountsService::saveAddress($account, $data);

        $sameAsCompany = $data['type'] != 'company' && $account->address_id == $address->id ? 1 : 0;

        return new AddressDetailResource($address, $sameAsCompany);
    }

    public function getSubscription($subscriptionId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $subscription = Subscription::find($subscriptionId);

        return new SubscriptionDetailResource($subscription);
    }

    public function getPastAccountSubscriptions($accountId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $pastSubscriptions = AccountsService::getAccountPastSubscriptions($account);

        return SubscriptionDetailResource::collection($pastSubscriptions);
    }

    public function cancelSubscription($subscriptionId, SubscriptionCancelRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $subscription = Subscription::find($subscriptionId);

        if (!$subscription) {
            abort(404);
        }

        $cancellationData = $request->validated();

        $subscription = AccountsService::cancelSubscription($subscription, $cancellationData);

        return new SubscriptionDetailResource($subscription);
    }

    public function renewSubscription($subscriptionId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $subscription = Subscription::find($subscriptionId);

        if (!$subscription) {
            abort(404);
        }

        $subscription = AccountsService::renewSubscription($subscription);

        return new SubscriptionDetailResource($subscription);
    }

    public function activateSubscription($subscriptionId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $subscription = Subscription::find($subscriptionId);

        if (!$subscription) {
            abort(404);
        }

        $subscription = AccountsService::activateSubscription($subscription);

        return new SubscriptionDetailResource($subscription);
    }

    public function updateSubscription($subscriptionId, SubscriptionCreateUpdateRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $data = $request->validated();

        $subscription = Subscription::find($subscriptionId);

        if (!$subscription) {
            abort(404);
        }

        $subscription = AccountsService::saveSubscription($subscription, $data);

        return new SubscriptionDetailResource($subscription);
    }

    public function createSubscription(SubscriptionCreateUpdateRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $data = $request->validated();

        $account = Account::find($data['accountId']);

        if (!$account) {
            abort(404);
        }

        $subscription = AccountsService::createSubscription($account, $data);

        return new SubscriptionDetailResource($subscription);
    }

    /* BO Function */
    public function getCreate()
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        return Inertia::render('Backoffice/Accounts/CreateAccount', []);
    }

    public function postCreate(AccountCreateRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $data = $request->validated();

        if ($data['createUser'] && User::where('email', $data['userEmail'])->exists()) {
            return response()->json([
                'errors' => [
                    'userEmail' => ['A user with this email already exists.']
                ]
            ], 422);
        }

        $account = AccountsService::createAccount($data);

        return new AccountDetailResource($account);
    }

    /* Method to retrieve Accounts list for SelectModel property in SelectBox */
    public function postAccountsAutoComplete(AdminContentAutoComplete $request)
    {
        $data = $request->validated();
        $searchTerm = urldecode($data['searchTerm']);
        $exactId = !empty($data['id']) ? $data['id'] : null;

        $query = Account::select('id', 'company as title');

        if (!empty($searchTerm)) {
            $query->where('company', 'like', "%$searchTerm%");
        }

        if (!is_null($exactId)) {
            $query->where('id', $exactId);
        }

        $query->orderBy('company', 'ASC');

        $accounts = $query->limit(5)->get();

        return response()->json($accounts, 200);
    }

    public function getMembers($accountId, BasicListingRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $data = $request->validated();

        $members = AccountsService::adminGetMembers($account, $data);

        return MemberResource::collection($members);
    }

    public function inviteMember($accountId, AccountMemberInviteRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $data = $request->validated();

        $member = AccountsService::adminInviteMember($account, $data);

        return new MemberResource($member);
    }

    public function attachMember($accountId, Request $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $data = $request->validate([
            'userId' => 'required|integer|exists:users,id',
            'isAdmin' => 'required|boolean',
        ]);

        $member = AccountsService::adminAttachMember($account, $data);

        return new MemberResource($member);
    }

    public function updateMember($accountId, $memberId, AccountMemberAdminStatus $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $data = $request->validated();

        $member = AccountsService::adminUpdateMember($account, $memberId, $data);

        return new MemberResource($member);
    }

    public function deleteMember($accountId, $memberId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $member = AccountsService::adminDeleteMember($account, $memberId);

        return response()->json(['success' => $member != null]);
    }

    // Invoice Methods
    public function getInvoices($accountId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $invoices = $account->invoices()->orderBy('date', 'desc')->get();

        return AccountInvoiceResource::collection($invoices);
    }

    public function getInvoice($accountId, $invoiceId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $invoice = AccountInvoice::where('account_id', $accountId)
            ->where('id', $invoiceId)
            ->first();

        if (!$invoice) {
            abort(404);
        }

        return new AccountInvoiceResource($invoice);
    }

    public function storeInvoice($accountId, AccountInvoiceRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $account = Account::find($accountId);

        if (!$account) {
            abort(404);
        }

        $data = $request->validated();

        $invoice = new AccountInvoice();
        $invoice->account_id = $accountId;
        $invoice->invoice_number = $data['invoiceNumber'];
        $invoice->amount = $data['amount'];
        $invoice->currency = $data['currency'];
        $invoice->status = $data['status'];
        $invoice->date = $data['date'];
        $invoice->media_id = !empty($data['mediaIds']) ? $data['mediaIds'][0] : null;
        $invoice->save();

        return new AccountInvoiceResource($invoice);
    }

    public function updateInvoice($accountId, $invoiceId, AccountInvoiceRequest $request)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $invoice = AccountInvoice::where('account_id', $accountId)
            ->where('id', $invoiceId)
            ->first();

        if (!$invoice) {
            abort(404);
        }

        $data = $request->validated();

        $invoice->invoice_number = $data['invoiceNumber'];
        $invoice->amount = $data['amount'];
        $invoice->currency = $data['currency'];
        $invoice->status = $data['status'];
        $invoice->date = $data['date'];
        $invoice->media_id = !empty($data['mediaIds']) ? $data['mediaIds'][0] : null;
        $invoice->save();

        return new AccountInvoiceResource($invoice);
    }

    public function deleteInvoice($accountId, $invoiceId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if (!$loggedUser->hasPermission("accounts.manage")) {
            abort(403);
        }

        $invoice = AccountInvoice::where('account_id', $accountId)
            ->where('id', $invoiceId)
            ->first();

        if (!$invoice) {
            abort(404);
        }

        $invoice->delete();

        return response()->json(['message' => 'Invoice deleted successfully']);
    }
}
