<?php

namespace App\Http\Controllers\Inquiry;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Inquiry\SubmitInquiryRequest;
use App\Models\Agent;
use App\Models\CityTranslation;
use App\Models\Inquiry;
use App\Models\Language;
use App\Models\Person;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

/**
 * @OA\Post(
 *   path="/api/inquiry",
 *   tags={"Inquiry"},
 *   summary="Submit Inquiry",
 *   operationId="inquiry_submit",
 *   security={{"auth":{}}},
 *
 *   @OA\Parameter(name="Accept-Language", in="header", description="Accept-Language", required=true, example="en", @OA\Schema(type="string")),
 *   @OA\Parameter(name="API-Key", in="header", description="API-Key", required=true, example="", @OA\Schema(type="string")),
 *
 *   @OA\RequestBody(required=true,
 *     @OA\MediaType(mediaType="application/x-www-form-urlencoded",
 *       @OA\Schema(required={"address", "arrived_at", "birthdays", "city", "deductible_ids", "email", "ended_at", "first_names", "genders", "insurance_cover", "is_entry", "last_names", "phone", "postal_code", "price_ids", "province_id", "started_at"},
 *         @OA\Property(property="address", description="Address", type="string", example=""),
 *         @OA\Property(property="arrived_at", description="Arrived At YYYY-MM-DD", type="string", example=""),
 *         @OA\Property(property="birthdays", description="Birthdays YYYY-MM-DD (CSV)", type="string", example=""),
 *         @OA\Property(property="card_cvv", description="Card CVV", type="string", example=""),
 *         @OA\Property(property="card_expiration", description="Card Expiration YYYY-MM-DD", type="string", example=""),
 *         @OA\Property(property="card_name", description="Card Holder Name", type="string", example=""),
 *         @OA\Property(property="card_number", description="Card Number (16 Digits PAN)", type="string", example=""),
 *         @OA\Property(property="city", description="City Name", type="string", example=""),
 *         @OA\Property(property="deductible_ids", description="Deductible IDs (CSV)", type="string", example=""),
 *         @OA\Property(property="email", description="Email", type="string", example=""),
 *         @OA\Property(property="ended_at", description="Ended At YYYY-MM-DD", type="string", example=""),
 *         @OA\Property(property="first_names", description="First Names (CSV)", type="string", example=""),
 *         @OA\Property(property="genders", description="Genders (CSV)", type="string", example=""),
 *         @OA\Property(property="insurance_cover", description="Insurance Cover", type="string", example=""),
 *         @OA\Property(property="is_entry", description="Is Entry (0|1)", type="string", example=""),
 *         @OA\Property(property="last_names", description="Last Names (CSV)", type="string", example=""),
 *         @OA\Property(property="message", description="Message", type="string", example=""),
 *         @OA\Property(property="phone", description="Phone", type="string", example=""),
 *         @OA\Property(property="postal_code", description="Postal Code", type="string", example=""),
 *         @OA\Property(property="price_ids", description="Price IDs (CSV)", type="string", example=""),
 *         @OA\Property(property="province_id", description="Province ID", type="string", example=""),
 *         @OA\Property(property="started_at", description="Started At YYYY-MM-DD", type="string", example=""),
 *         @OA\Property(property="transfer_password", description="Transfer Password", type="string", example=""),
 *       )
 *     )
 *   ),
 *
 *   @OA\Response(response=200, description="success")
 * )
 */
class SubmitInquityController extends ApiController
{
    public function __invoke(SubmitInquiryRequest $request): JsonResponse
    {
        try {
            DB::transaction(function () use ($request) {
                $data = $this->sanitize($request, [
                    'address'           => $request->validated('address'),
                    'apiKey'            => $request->validated('apiKey'),
                    'arrived_at'        => $request->validated('arrived_at'),
                    'birthdays'         => $request->validated('birthdays'),
                    'card_cvv'          => $request->validated('card_cvv'),
                    'card_expiration'   => $request->validated('card_expiration'),
                    'card_name'         => $request->validated('card_name'),
                    'card_number'       => $request->validated('card_number'),
                    'city'              => $request->validated('city'),
                    'deductible_ids'    => $request->validated('deductible_ids'),
                    'email'             => $request->validated('email'),
                    'ended_at'          => $request->validated('ended_at'),
                    'first_names'       => $request->validated('first_names'),
                    'genders'           => $request->validated('genders'),
                    'insurance_cover'   => $request->validated('insurance_cover'),
                    'is_entry'          => $request->validated('is_entry'),
                    'last_names'        => $request->validated('last_names'),
                    'message'           => $request->validated('message'),
                    'phone'             => $request->validated('phone'),
                    'postal_code'       => $request->validated('postal_code'),
                    'price_ids'         => $request->validated('price_ids'),
                    'province_id'       => $request->validated('province_id'),
                    'started_at'        => $request->validated('started_at'),
                    'token'             => $request->validated('token'),
                    'transfer_password' => $request->validated('transfer_password'),
                ]);

                throw_if(
                    count(array_unique([count($data['birthdays']), count($data['first_names']), count($data['last_names']), count($data['genders']), count($data['deductible_ids']), count($data['price_ids'])])) !== 1,
                    new Exception('The count of "Birthdays", "First Names", "Last Names", "Genders", "Deductible IDs" and "Price IDs" must be the same.', Response::HTTP_BAD_REQUEST)
                );

                if ($cityTranslation = CityTranslation::query()->where('name', $data['city'])->first()) {
                    $cityId = $cityTranslation->city_id;
                } else {
                    $city = trim($data['city']);
                    $cityId = DB::table('cities')->insertGetId([
                        'province_id' => $data['province_id'],
                        'slug'        => Str::slug($city) . '-' . DB::table('cities')->max('id') + 1,
                    ]);
                    foreach (Language::query()->orderBy('id')->pluck('id')->toArray() as $languageId) {
                        DB::table('city_translations')->insert([
                            'city_id'     => $cityId,
                            'language_id' => $languageId,
                            'name'        => $city,
                        ]);
                    }
                }

                $inquiry = Inquiry::query()->create([
                    'agent_id'               => Agent::query()->where('id', $data['apiKey'])->value('id'),
                    'city_id'                => $cityId,
                    'insurance_cover'        => $data['insurance_cover'],
                    'address'                => $data['address'],
                    'postal_code'            => $data['postal_code'],
                    'phone'                  => $data['phone'],
                    'email'                  => $data['email'],
                    'card_number'            => $data['card_number'] ?? null,
                    'card_cvv'               => $data['card_cvv'] ?? null,
                    'card_name'              => $data['card_name'] ?? null,
                    'card_expiration'        => isset($data['card_expiration']) ? (new Carbon($data['card_expiration']))->format('ym') : null,
                    'transfer_password'      => $data['transfer_password'] ?? null,
                    'message'                => $data['message'] ?? null,
                    'beneficiary_first_name' => array_shift($data['first_names']),
                    'beneficiary_last_name'  => array_shift($data['last_names']),
                    'beneficiary_born_at'    => array_shift($data['birthdays']),
                    'started_at'             => new Carbon($data['started_at']),
                    'ended_at'               => new Carbon($data['ended_at']),
                    'arrived_at'             => new Carbon($data['arrived_at']),
                    'inquired_at'            => now(),
                    'is_beneficiary_male'    => array_shift($data['genders']) === 'Male',
                    'is_entry'               => $data['is_entry'],
                ]);

                array_shift($data['deductible_ids']);
                array_shift($data['price_ids']);

                $count = count($data['birthdays']);
                for ($i = 0; $i < $count; $i++) {
                    Person::query()->insert([
                        'id'            => Str::ulid()->toString(),
                        'inquiry_id'    => $inquiry->id,
                        'deductible_id' => $data['deductible_ids'][$i],
                        'price_id'      => $data['price_ids'][$i],
                        'first_name'    => $data['first_names'][$i],
                        'last_name'     => $data['last_names'][$i],
                        'born_at'       => $data['birthdays'][$i],
                        'is_male'       => $data['genders'][$i] === 'Male',
                    ]);
                }
            });
            return $this->success();
        } catch (Throwable $e) {
            return $this->error($e->getMessage(), status: $e->getCode());
        }
    }
}
