<?php

namespace App\Modules\CustomerPortal\Controllers;

use App\Http\Controllers\Controller;
use App\Http\Responses\ApiResponse;
use App\Modules\CustomerPortal\Models\CustomerPortalAccount;
use App\Modules\CustomerPortal\Requests\SaveCustomerPortalAccountRequest;
use App\Modules\CustomerPortal\Requests\StoreCustomerPortalAccountRequest;
use App\Modules\CustomerPortal\Requests\UpdateCustomerPortalAccountRequest;
use App\Modules\CustomerPortal\Resources\CustomerPortalAccountResource;
use App\Modules\Invoice\Models\Customer;
use App\Modules\Tenant\Models\Company;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class TenantPortalAccountController extends Controller
{
    public function show(Request $request, Customer $customer): JsonResponse
    {
        $company = $this->currentCompany($request);

        if ((int) $customer->company_id !== (int) $company->id) {
            return ApiResponse::error('Customer not found', 404);
        }

        $account = $customer->portalAccount()
            ->where('company_id', $company->id)
            ->first();

        if (! $account) {
            return ApiResponse::error('Customer portal account not found', 404);
        }

        return ApiResponse::success(
            new CustomerPortalAccountResource($account->load(['customer', 'company']))
        );
    }

    public function save(SaveCustomerPortalAccountRequest $request, Customer $customer): JsonResponse
    {
        $company = $this->currentCompany($request);

        if ((int) $customer->company_id !== (int) $company->id) {
            return ApiResponse::error('Customer not found', 404);
        }

        $account = $customer->portalAccount()
            ->where('company_id', $company->id)
            ->first();
        $data = $request->validated();

        if (! $account && blank($data['password'] ?? null)) {
            return ApiResponse::error('Password is required when creating a portal account', 422);
        }

        if ($account && array_key_exists('password', $data) && blank($data['password'])) {
            unset($data['password']);
        }

        if ($account) {
            $passwordChanged = array_key_exists('password', $data);
            $account->update($data);
            $this->revokeCustomerTokensWhenNeeded($account, $passwordChanged);

            return ApiResponse::success(
                new CustomerPortalAccountResource($account->fresh(['customer', 'company'])),
                'Customer portal account updated successfully'
            );
        }

        $account = CustomerPortalAccount::query()->create([
            'company_id' => $company->id,
            'customer_id' => $customer->id,
            'name' => $data['name'] ?? $customer->name,
            'email' => $data['email'],
            'password' => $data['password'],
            'status' => $data['status'] ?? 'active',
        ]);

        return ApiResponse::success(
            new CustomerPortalAccountResource($account->load(['customer', 'company'])),
            'Customer portal account created successfully',
            201
        );
    }

    public function store(StoreCustomerPortalAccountRequest $request, Customer $customer): JsonResponse
    {
        $company = $this->currentCompany($request);

        if ((int) $customer->company_id !== (int) $company->id) {
            return ApiResponse::error('Customer not found', 404);
        }

        if ($customer->portalAccount()->exists()) {
            return ApiResponse::error('Customer portal account already exists', 422);
        }

        $data = $request->validated();
        $account = CustomerPortalAccount::query()->create([
            'company_id' => $company->id,
            'customer_id' => $customer->id,
            'name' => $data['name'] ?? $customer->name,
            'email' => $data['email'],
            'password' => $data['password'],
            'status' => $data['status'] ?? 'active',
        ]);

        return ApiResponse::success(
            new CustomerPortalAccountResource($account->load(['customer', 'company'])),
            'Customer portal account created successfully',
            201
        );
    }

    public function update(UpdateCustomerPortalAccountRequest $request, Customer $customer): JsonResponse
    {
        $company = $this->currentCompany($request);

        if ((int) $customer->company_id !== (int) $company->id) {
            return ApiResponse::error('Customer not found', 404);
        }

        $account = $customer->portalAccount()
            ->where('company_id', $company->id)
            ->first();

        if (! $account) {
            return ApiResponse::error('Customer portal account not found', 404);
        }

        $data = $request->validated();

        if (array_key_exists('password', $data) && blank($data['password'])) {
            unset($data['password']);
        }

        $passwordChanged = array_key_exists('password', $data);
        $account->update($data);
        $this->revokeCustomerTokensWhenNeeded($account, $passwordChanged);

        return ApiResponse::success(
            new CustomerPortalAccountResource($account->fresh(['customer', 'company'])),
            'Customer portal account updated successfully'
        );
    }

    public function revokeTokens(Request $request, Customer $customer): JsonResponse
    {
        $company = $this->currentCompany($request);

        if ((int) $customer->company_id !== (int) $company->id) {
            return ApiResponse::error('Customer not found', 404);
        }

        $account = $customer->portalAccount()
            ->where('company_id', $company->id)
            ->first();

        if (! $account) {
            return ApiResponse::error('Customer portal account not found', 404);
        }

        $account->tokens()->delete();

        return ApiResponse::success(
            new CustomerPortalAccountResource($account->load(['customer', 'company'])),
            'Customer portal sessions revoked successfully'
        );
    }

    private function currentCompany(Request $request): Company
    {
        return $request->attributes->get('currentCompany');
    }

    private function revokeCustomerTokensWhenNeeded(CustomerPortalAccount $account, bool $passwordChanged): void
    {
        if ($passwordChanged || $account->status === 'inactive') {
            $account->tokens()->delete();
        }
    }
}
