<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\ChangePasswordRequest;
use App\Http\Requests\Auth\LoginRequest;
use App\Http\Requests\Auth\RegisterRequest;
use App\Http\Requests\Auth\UpdateProfileRequest;
use App\Models\Address;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;

class AuthController extends Controller
{
    public function register(RegisterRequest $request): JsonResponse
    {
        $user = User::create([
            'name'                    => $request->name,
            'email'                   => $request->email,
            'password'                => Hash::make($request->password),
            'date_of_birth'           => $request->date_of_birth,
            'age_verified_at'         => now(),
            'phone'                   => $request->phone,
            'email_marketing_consent' => (bool) $request->input('email_marketing_consent', false),
        ]);

        if ($user->email_marketing_consent) {
            \App\Models\EmailSubscriber::firstOrCreate(
                ['email' => strtolower($user->email)],
                ['subscribed_at' => now(), 'source' => 'registration']
            );
        }

        $user->assignRole('customer');

        event(new Registered($user));

        $token = $user->createToken('auth_token')->plainTextToken;

        return response()->json([
            'user' => $user,
            'token' => $token,
            'message' => 'Registration successful. Please verify your email.',
        ], 201);
    }

    public function login(LoginRequest $request): JsonResponse
    {
        if (!Auth::attempt($request->only('email', 'password'))) {
            return response()->json([
                'message' => 'Invalid credentials.',
            ], 401);
        }

        $user = Auth::user();
        $user->tokens()->delete();
        $token = $user->createToken('auth_token')->plainTextToken;

        return response()->json([
            'user'  => array_merge($user->toArray(), ['roles' => $user->getRoleNames()]),
            'token' => $token,
        ]);
    }

    public function logout(Request $request): JsonResponse
    {
        $request->user()->currentAccessToken()->delete();

        return response()->json(['message' => 'Logged out successfully.']);
    }

    public function me(Request $request): JsonResponse
    {
        $user = $request->user();
        return response()->json(array_merge($user->toArray(), [
            'roles' => $user->getRoleNames(),
        ]));
    }

    public function loyaltyTransactions(Request $request): JsonResponse
    {
        $transactions = $request->user()
            ->loyaltyTransactions()
            ->with('order:id,order_number')
            ->orderByDesc('created_at')
            ->limit(50)
            ->get()
            ->map(fn($t) => [
                'id'           => $t->id,
                'points'       => $t->points,
                'type'         => $t->type,
                'description'  => $t->description,
                'order_number' => $t->order?->order_number,
                'created_at'   => $t->created_at,
            ]);

        return response()->json([
            'balance'      => $request->user()->loyalty_points,
            'transactions' => $transactions,
        ]);
    }

    public function orders(Request $request): JsonResponse
    {
        $orders = $request->user()
            ->orders()
            ->with(['items', 'shippingAddress'])
            ->orderByDesc('created_at')
            ->get()
            ->map(fn($o) => [
                'id'           => $o->id,
                'order_number' => $o->order_number,
                'status'       => $o->status,
                'total'        => $o->total,
                'items_count'  => $o->items->count(),
                'created_at'   => $o->created_at,
                'tracking_number' => $o->tracking_number,
            ]);

        return response()->json(['data' => $orders]);
    }

    public function addresses(Request $request): JsonResponse
    {
        $addresses = $request->user()->addresses()
            ->orderByDesc('is_default')
            ->orderByDesc('created_at')
            ->get();

        return response()->json(['data' => $addresses]);
    }

    public function storeAddress(Request $request): JsonResponse
    {
        $data = $request->validate([
            'first_name'     => 'required|string|max:100',
            'last_name'      => 'required|string|max:100',
            'address_line_1' => 'required|string|max:255',
            'address_line_2' => 'nullable|string|max:255',
            'city'           => 'required|string|max:100',
            'county'         => 'nullable|string|max:100',
            'postcode'       => 'required|string|max:20',
            'country'        => 'required|string|max:100',
            'phone'          => 'nullable|string|max:30',
            'is_default'     => 'boolean',
        ]);

        $user = $request->user();

        if (!empty($data['is_default'])) {
            $user->addresses()->update(['is_default' => false]);
        }

        // First address is always default
        if ($user->addresses()->count() === 0) {
            $data['is_default'] = true;
        }

        $address = $user->addresses()->create(array_merge($data, ['type' => 'shipping']));

        return response()->json(['data' => $address], 201);
    }

    public function updateAddress(Request $request, int $id): JsonResponse
    {
        $address = $request->user()->addresses()->findOrFail($id);

        $data = $request->validate([
            'first_name'     => 'sometimes|string|max:100',
            'last_name'      => 'sometimes|string|max:100',
            'address_line_1' => 'sometimes|string|max:255',
            'address_line_2' => 'nullable|string|max:255',
            'city'           => 'sometimes|string|max:100',
            'county'         => 'nullable|string|max:100',
            'postcode'       => 'sometimes|string|max:20',
            'country'        => 'sometimes|string|max:100',
            'phone'          => 'nullable|string|max:30',
            'is_default'     => 'boolean',
        ]);

        if (!empty($data['is_default'])) {
            $request->user()->addresses()->where('id', '!=', $id)->update(['is_default' => false]);
        }

        $address->update($data);

        return response()->json(['data' => $address]);
    }

    public function destroyAddress(Request $request, int $id): JsonResponse
    {
        $address = $request->user()->addresses()->findOrFail($id);
        $wasDefault = $address->is_default;
        $address->delete();

        // Promote next address to default
        if ($wasDefault) {
            $request->user()->addresses()->latest()->first()?->update(['is_default' => true]);
        }

        return response()->json(['message' => 'Address deleted.']);
    }

    public function updateProfile(UpdateProfileRequest $request): JsonResponse
    {
        $user = $request->user();

        $updates = [];
        if ($request->exists('name'))  $updates['name']  = $request->input('name');
        if ($request->exists('email')) $updates['email'] = $request->input('email');
        if ($request->exists('phone')) $updates['phone'] = $request->input('phone') ?: null;

        $consentChanged = $request->exists('email_marketing_consent');
        if ($consentChanged) {
            $updates['email_marketing_consent'] = filter_var($request->input('email_marketing_consent'), FILTER_VALIDATE_BOOLEAN);
        }

        if (!empty($updates)) {
            $user->update($updates);
        }

        // Sync newsletter subscription when consent changes
        if ($consentChanged) {
            $email = strtolower($user->email);
            if ($updates['email_marketing_consent']) {
                \App\Models\EmailSubscriber::updateOrCreate(
                    ['email' => $email],
                    ['unsubscribed_at' => null, 'subscribed_at' => now(), 'source' => 'account_settings']
                );
            } else {
                \App\Models\EmailSubscriber::where('email', $email)
                    ->whereNull('unsubscribed_at')
                    ->update(['unsubscribed_at' => now()]);
            }
        }

        $fresh = $user->fresh();
        return response()->json([
            'id'                       => $fresh->id,
            'name'                     => $fresh->name,
            'email'                    => $fresh->email,
            'phone'                    => $fresh->phone,
            'email_marketing_consent'  => (bool) $fresh->email_marketing_consent,
            'loyalty_points'           => $fresh->loyalty_points,
            'age_verified_at'          => $fresh->age_verified_at,
            'email_verified_at'        => $fresh->email_verified_at,
        ]);
    }

    public function changePassword(ChangePasswordRequest $request): JsonResponse
    {
        $request->user()->update([
            'password' => Hash::make($request->password),
        ]);

        $request->user()->tokens()->delete();
        $token = $request->user()->createToken('auth_token')->plainTextToken;

        return response()->json([
            'message' => 'Password changed successfully.',
            'token' => $token,
        ]);
    }

    public function forgotPassword(Request $request): JsonResponse
    {
        $request->validate(['email' => 'required|email']);

        $status = Password::sendResetLink($request->only('email'));

        return response()->json([
            'message' => __($status),
        ], $status === Password::RESET_LINK_SENT ? 200 : 422);
    }

    public function resetPassword(Request $request): JsonResponse
    {
        $request->validate([
            'token' => 'required',
            'email' => 'required|email',
            'password' => 'required|confirmed|min:8',
        ]);

        $status = Password::reset(
            $request->only('email', 'password', 'password_confirmation', 'token'),
            function (User $user, string $password) {
                $user->update(['password' => Hash::make($password)]);
                $user->tokens()->delete();
            }
        );

        return response()->json([
            'message' => __($status),
        ], $status === Password::PASSWORD_RESET ? 200 : 422);
    }

    public function discountCodes(Request $request): JsonResponse
    {
        $user = $request->user();

        // Codes belonging to the user directly
        $personal = \App\Models\DiscountCode::where('user_id', $user->id)
            ->where('is_active', true)
            ->orderByDesc('created_at')
            ->get();

        // Welcome codes created for this email (WELCOME15-XXXXXX pattern where suffix = md5 of email)
        $emailPrefix = 'WELCOME15-' . strtoupper(substr(md5(strtolower($user->email)), 0, 6));
        $welcome = \App\Models\DiscountCode::where('code', $emailPrefix)
            ->where('is_active', true)
            ->whereNull('user_id')
            ->get();

        $codes = $personal->merge($welcome)->map(fn($c) => [
            'code'       => $c->code,
            'type'       => $c->type,
            'value'      => (float) $c->value,
            'expires_at' => $c->expires_at?->toDateString(),
            'uses_count' => $c->uses_count,
            'max_uses'   => $c->max_uses,
            'is_used'    => $c->max_uses && $c->uses_count >= $c->max_uses,
        ]);

        return response()->json(['data' => $codes]);
    }

    public function deleteAccount(Request $request): JsonResponse
    {
        $user = $request->user();
        $user->tokens()->delete();
        $user->delete();

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

    public function googleRedirect(): JsonResponse
    {
        return response()->json([
            'url' => \Laravel\Socialite\Facades\Socialite::driver('google')->stateless()->redirect()->getTargetUrl(),
        ]);
    }

    public function googleCallback(): JsonResponse
    {
        try {
            $googleUser = \Laravel\Socialite\Facades\Socialite::driver('google')->stateless()->user();
        } catch (\Exception $e) {
            return response()->json(['message' => 'Google authentication failed.'], 422);
        }

        $user = User::firstOrCreate(
            ['email' => $googleUser->getEmail()],
            [
                'name' => $googleUser->getName(),
                'google_id' => $googleUser->getId(),
                'age_verified_at' => null,
            ]
        );

        if (!$user->google_id) {
            $user->update(['google_id' => $googleUser->getId()]);
        }

        if (!$user->hasRole('customer')) {
            $user->assignRole('customer');
        }

        $token = $user->createToken('auth_token')->plainTextToken;

        return response()->json([
            'user' => $user,
            'token' => $token,
            'requires_age_verification' => !$user->isAgeVerified(),
        ]);
    }

    public function facebookRedirect(): JsonResponse
    {
        return response()->json([
            'url' => \Laravel\Socialite\Facades\Socialite::driver('facebook')->stateless()->redirect()->getTargetUrl(),
        ]);
    }

    public function facebookCallback(): JsonResponse
    {
        try {
            $fbUser = \Laravel\Socialite\Facades\Socialite::driver('facebook')->stateless()->user();
        } catch (\Exception $e) {
            return response()->json(['message' => 'Facebook authentication failed.'], 422);
        }

        $user = User::firstOrCreate(
            ['email' => $fbUser->getEmail()],
            [
                'name' => $fbUser->getName(),
                'facebook_id' => $fbUser->getId(),
                'age_verified_at' => null,
            ]
        );

        if (!$user->facebook_id) {
            $user->update(['facebook_id' => $fbUser->getId()]);
        }

        if (!$user->hasRole('customer')) {
            $user->assignRole('customer');
        }

        $token = $user->createToken('auth_token')->plainTextToken;

        return response()->json([
            'user' => $user,
            'token' => $token,
            'requires_age_verification' => !$user->isAgeVerified(),
        ]);
    }

    public function verifyAge(Request $request): JsonResponse
    {
        $request->validate([
            'date_of_birth' => ['required', 'date', 'before:-18 years'],
        ], [
            'date_of_birth.before' => 'You must be at least 18 years old.',
        ]);

        $request->user()->update([
            'date_of_birth' => $request->date_of_birth,
            'age_verified_at' => now(),
        ]);

        return response()->json([
            'message' => 'Age verified successfully.',
            'user' => $request->user()->fresh(),
        ]);
    }
}
