<?php

namespace App\Http\Controllers\Api\V1;

use App\Helpers\ApiResponse;
use App\Helpers\LanguageHelper;
use App\Http\Controllers\Controller;
use App\Models\FranchiseAddress; // ✅ ADD
use App\Models\Franchisee;
use App\Models\Setting;
use App\Models\User;
use App\Services\GeocodingService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Rule;
use Symfony\Component\HttpFoundation\Response;

/**
 * FranchiseeController
 *
 * Handles create/update (idempotent sync) of franchisees
 * from Zoho using franchise_domain + crm_record_id.
 */
class FranchiseeController extends Controller
{
    /**
     * Create or Update a Franchisee
     *
     * @OA\Post(
     *     path="/api/v1/franchisees/add",
     *     summary="Create or update a franchisee",
     *     description="Creates or updates a franchisee based on franchise_domain and crm_record_id (crm_id).
     *                  Normalizes language, creates admin user and default settings only on first creation.",
     *     tags={"Authorization"},
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={
     *                 "crm_id",
     *                 "name",
     *                 "franchise_domain",
     *                 "zoho_franchise_id",
     *                 "owner_name",
     *                 "email",
     *                 "phone",
     *                 "status"
     *             },
     *             @OA\Property(property="crm_id", type="string", example="12345UUID"),
     *             @OA\Property(property="zoho_franchise_id", type="string", example="ZOHO-987654"),
     *             @OA\Property(property="name", type="string", example="ABC Franchise"),
     *             @OA\Property(property="franchise_domain", type="string", example="abcfranchise.com"),
     *             @OA\Property(property="is_custom_domain", type="boolean", example=true),
     *             @OA\Property(property="owner_name", type="string", example="Alice Smith"),
     *             @OA\Property(property="email", type="string", format="email", example="alice@example.com"),
     *             @OA\Property(property="phone", type="string", example="1234567890"),
     *             @OA\Property(property="status", type="string", enum={"active","disabled"}, example="active"),
     *             @OA\Property(property="language", type="string", example="en"),
     *
     *             @OA\Property(property="territory_country", type="string", example="India"),
     *             @OA\Property(property="territory_state", type="string", example="Punjab"),
     *             @OA\Property(property="territory_city", type="string", example="Ludhiana"),
     *             @OA\Property(property="postal_code", type="string", example="141001"),
     *             @OA\Property(property="address", type="string", example="Model Town, Near XYZ Mall")
     *         )
     *     ),
     *     @OA\Response(
     *         response=201,
     *         description="Franchisee created successfully."
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Franchisee updated successfully."
     *     ),
     *     @OA\Response(
     *         response=400,
     *         description="Validation or payload error."
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="Invalid signature."
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Unexpected server error."
     *     )
     * )
     */
    public function store(Request $request, GeocodingService $geocoder)
    {
        try {
            /**
             * 1) Validation
             * NOTE: No unique constraints here (handled via updateOrCreate).
             * crm_id and zoho_franchise_id are distinct identifiers: `franchisees`
             * is keyed on crm_record_id while `franchise_addresses` is keyed on
             * zoho_franchise_id in the transaction below.
             */
            $validated = $request->validate([
                'crm_id' => 'required|string',
                'name' => 'required|string',
                'franchise_domain' => 'required|string',

                // keep existing field (do not break payload)
                'zoho_franchise_id' => 'required|string',

                'is_custom_domain' => 'boolean',
                'owner_name' => 'required|string',
                'email' => 'required|email',
                'phone' => 'required|string',
                'status' => ['required', Rule::in(['active', 'disabled'])],
                'language' => 'nullable|string',

                // Country is required so lat/long can always be geocoded;
                // state/city/postal/address are optional refinements.
                'territory_country' => 'required|string',
                'territory_state' => 'nullable|string',
                'territory_city' => 'nullable|string',
                'postal_code' => 'nullable|string',
                'address' => 'nullable|string',
            ]);

            $crmId = $validated['crm_id'];

            /**
             * 3) Normalize language
             */
            $languageName = $request->input('language');
            $validated['language'] = LanguageHelper::mapLanguageToCode($languageName);

            /**
             * 3.1) Geocode (lat/long) using service.
             * territory_country is required by validation above, so a query
             * can always be built.
             */
            $latitude = null;
            $longitude = null;
            $geocodeWarning = null;

            $geoQuery = $geocoder->buildQuery($validated);
            $coords = $geoQuery ? $geocoder->geocode($geoQuery, $validated['franchise_domain'] ?? null) : [];
            $latitude = $coords['lat'] ?? null;
            $longitude = $coords['lng'] ?? null;

            if ($latitude === null || $longitude === null) {
                $geocodeWarning = 'Geocode returned empty coordinates for the given address.';
                Log::warning('Geocode returned empty coordinates', ['query' => $geoQuery]);
            }

            /**
             * 4) Create or Update Franchisee
             */
            $result = DB::transaction(function () use ($validated, $languageName, $crmId, $latitude, $longitude) {

                $franchisee = Franchisee::updateOrCreate(
                    [
                        'crm_record_id' => $crmId,
                    ],
                    [
                        'name' => $validated['name'],
                        'owner_name' => $validated['owner_name'],
                        'email' => $validated['email'],
                        'phone' => $validated['phone'],
                        'status' => $validated['status'],
                        'franchise_domain' => $validated['franchise_domain'],
                        'language' => $validated['language'],
                        'is_custom_domain' => $validated['is_custom_domain'] ?? false,

                        // keep existing field stored (do not remove)
                        'zoho_franchise_id' => $validated['zoho_franchise_id'],

                        // NEW: save territory fields
                        'territory_country' => $validated['territory_country'] ?? null,
                        'territory_state' => $validated['territory_state'] ?? null,
                        'territory_city' => $validated['territory_city'] ?? null,

                        // NEW: save address fields
                        'postal_code' => $validated['postal_code'] ?? null,
                        'address' => $validated['address'] ?? null,

                        // NEW: save lat/long
                        'latitude' => $latitude,
                        'longitude' => $longitude,
                    ]
                );

                // ✅ NEW: also upsert into franchise_addresses with status
                FranchiseAddress::updateOrCreate(
                    [
                        'zoho_franchise_id' => $validated['zoho_franchise_id'],
                    ],
                    [
                        'status' => $validated['status'],
                        'territory_country' => $validated['territory_country'] ?? null,
                        'territory_state' => $validated['territory_state'] ?? null,
                        'territory_city' => $validated['territory_city'] ?? null,
                        'postal_code' => $validated['postal_code'] ?? null,
                        'address' => $validated['address'] ?? null,
                        'latitude' => $latitude,
                        'longitude' => $longitude,
                    ]
                );

                /**
                 * Create admin user & settings only once
                 */
                if ($franchisee->wasRecentlyCreated) {

                    User::create([
                        'franchisee_id' => $franchisee->id,
                        'name' => $franchisee->owner_name,
                        'email' => $franchisee->email,
                        'password' => Hash::make('Admin@12345'),
                        'role' => 'franchise_admin',
                    ]);

                    Setting::create([
                        'franchisee_id' => $franchisee->id,
                        'general_settings' => [
                            'language_code' => $validated['language'],
                            'language_name' => $languageName,
                        ],
                    ]);
                }

                return [
                    'franchisee' => $franchisee,
                    'created' => $franchisee->wasRecentlyCreated,
                ];
            });

            return response()->json(
                [
                    'status' => 'success',
                    'message' => $result['created']
                        ? 'Franchisee created successfully.'
                        : 'Franchisee updated successfully.',
                    'franchisee' => $result['franchisee'],
                    'geocode_warning' => $geocodeWarning,
                ],
                $result['created']
                ? Response::HTTP_CREATED
                : Response::HTTP_OK
            );

        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }
}
