<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\ExpenseCategory;
use App\Models\Organization;
use App\Models\Setting;
use App\Models\Subscription;
use App\Services\ActivityLogger;
use Illuminate\Http\Request;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use App\Models\User;
use Illuminate\Validation\ValidationException;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        $user = User::where('email', $request->email)->first();

        if (!$user || !Hash::check($request->password, $user->password)) {
            throw ValidationException::withMessages([
                'email' => ['The provided credentials are incorrect.'],
            ]);
        }

        if ($user->is_platform_admin) {
            throw ValidationException::withMessages([
                'email' => ['Platform administrators must sign in via the admin portal.'],
            ]);
        }

        if (!$user->is_active) {
            throw ValidationException::withMessages([
                'email' => ['Your account has been deactivated.'],
            ]);
        }

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

        // Track login as an activity event so DAU/WAU/MAU counters are accurate.
        // We must set the org context manually here because the SetTenantScope
        // middleware hasn't run yet (login is a public route).
        if ($user->organization_id) {
            app()->instance('current_organization_id', $user->organization_id);
        }
        ActivityLogger::log('user_login', "User {$user->name} signed in", null, null, null);

        $user->load('organization.subscription');
        $subscription = $user->organization?->subscription;
        if ($subscription) {
            $subscription->expireIfNeeded();
        }

        return response()->json([
            'user'              => $user->load('roles'),
            'permissions'       => $user->getAllPermissions()->pluck('name'),
            'token'             => $token,
            'email_verified'    => $user->hasVerifiedEmail(),
            'plan_features'     => $user->organization?->getPlanFeatures() ?? [],
            'org_features'      => $user->organization?->getOrgFeatures() ?? [],
            'subscription_info' => $subscription ? [
                'status'             => $subscription->status,
                'plan'               => $subscription->plan,
                'current_period_end' => $subscription->current_period_end?->toIso8601String(),
                'trial_ends_at'      => $subscription->trial_ends_at?->toIso8601String(),
            ] : null,
        ]);
    }

    public function platformLogin(Request $request)
    {
        $request->validate([
            'email'    => 'required|email',
            'password' => 'required',
        ]);

        $user = User::where('email', $request->email)->first();

        if (!$user || !Hash::check($request->password, $user->password)) {
            throw ValidationException::withMessages([
                'email' => ['The provided credentials are incorrect.'],
            ]);
        }

        if (!$user->is_platform_admin) {
            throw ValidationException::withMessages([
                'email' => ['This portal is for platform administrators only.'],
            ]);
        }

        if (!$user->is_active) {
            throw ValidationException::withMessages([
                'email' => ['Your account has been deactivated.'],
            ]);
        }

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

        return response()->json([
            'user'           => $user->load('roles'),
            'permissions'    => $user->getAllPermissions()->pluck('name'),
            'token'          => $token,
            'email_verified' => $user->hasVerifiedEmail(),
        ]);
    }

    public function register(Request $request)
    {
        $request->validate([
            'org_name' => 'required|string|max:255',
            'name'     => 'required|string|max:255',
            'email'    => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
            'phone'    => 'required|string|max:30',
            'country'  => 'required|string|max:100',
            'state'    => 'required|string|max:150',
        ]);

        // 1. Create the organisation
        $org = Organization::create([
            'name'      => $request->org_name,
            'slug'      => Str::slug($request->org_name) . '-' . Str::lower(Str::random(6)),
            'email'     => $request->email,
            'phone'     => $request->phone,
            'country'   => $request->country,
            'state'     => $request->state,
            'is_active' => true,
        ]);

        // 2. Create the admin user, tied to this org (email NOT yet verified)
        $user = User::create([
            'name'              => $request->name,
            'email'             => $request->email,
            'password'          => Hash::make($request->password),
            'phone'             => $request->phone,
            'is_active'         => true,
            'organization_id'   => $org->id,
            // email_verified_at intentionally null — verification email is sent below
        ]);

        // 3. Make them the org-owner (the only user who can manage other users)
        $user->assignRole('org-owner');

        // 4. Bind tenant scope so seeded records belong to this org
        app()->instance('current_organization_id', $org->id);

        // 5. Seed default expense categories for this org
        $defaultCategories = [
            'Rent & Utilities',
            'Salaries & Wages',
            'Supplies & Materials',
            'Marketing & Advertising',
            'Maintenance & Repairs',
            'Transportation & Fuel',
            'Insurance',
            'Miscellaneous',
        ];
        foreach ($defaultCategories as $cat) {
            ExpenseCategory::create(['name' => $cat, 'is_active' => true]);
        }

        // 6. Seed default settings for this org
        $defaultSettings = [
            ['key' => 'business_name',       'value' => $request->org_name,             'type' => 'string',  'description' => 'Business name for invoices and receipts'],
            ['key' => 'phone',             'value' => $request->phone ?? '',          'type' => 'string',  'description' => 'Business contact phone'],
            ['key' => 'email',             'value' => $request->email,                'type' => 'string',  'description' => 'Business contact email'],
            ['key' => 'address',           'value' => '',                             'type' => 'string',  'description' => 'Business address'],
            ['key' => 'business_logo',       'value' => null,                           'type' => 'string',  'description' => 'Business logo path'],
            ['key' => 'tax_rate',            'value' => '0',                            'type' => 'string',  'description' => 'Tax rate (e.g., 0.15 for 15%)'],
            ['key' => 'currency_symbol',     'value' => '$',                            'type' => 'string',  'description' => 'Currency symbol'],
            ['key' => 'currency_code',       'value' => 'USD',                          'type' => 'string',  'description' => 'Currency code'],
            ['key' => 'low_stock_threshold', 'value' => '10',                           'type' => 'integer', 'description' => 'Default low stock threshold'],
            ['key' => 'invoice_prefix',      'value' => 'INV',                          'type' => 'string',  'description' => 'Invoice number prefix'],
            ['key' => 'receipt_footer',      'value' => 'Thank you for your business!', 'type' => 'string',  'description' => 'Message at bottom of receipts'],
            ['key' => 'enable_loyalty_points','value'=> '1',                            'type' => 'boolean', 'description' => 'Enable customer loyalty points'],
            ['key' => 'loyalty_enabled',     'value' => '1',                            'type' => 'boolean', 'description' => 'Enable customer loyalty points program'],
            ['key' => 'loyalty_points_per_unit','value'=> '1',                          'type' => 'string',  'description' => 'Points earned per 1 unit of currency spent'],
            ['key' => 'loyalty_point_value', 'value' => '0.50',                         'type' => 'string',  'description' => 'Monetary value of each loyalty point'],
        ];
        foreach ($defaultSettings as $s) {
            Setting::create($s);
        }

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

        // 7. Create a 14-day free trial subscription
        $trialEndsAt  = now()->addDays(14);
        $subscription = Subscription::create([
            'organization_id'      => $org->id,
            'plan'                 => 'free',
            'status'               => 'trial',
            'amount'               => 0,
            'billing_cycle'        => 'monthly',
            'current_period_start' => now(),
            'trial_ends_at'        => $trialEndsAt,
        ]);

        // Send email verification immediately after registration
        // Welcome email is sent separately once the user verifies their address.
        try {
            $user->sendEmailVerificationNotification();
        } catch (\Throwable $e) {
            Log::warning('Failed to send verification email on registration.', ['email' => $user->email, 'error' => $e->getMessage()]);
        }

        return response()->json([
            'user'              => $user->load('roles'),
            'permissions'       => $user->getAllPermissions()->pluck('name'),
            'token'             => $token,
            'email_verified'    => false,
            'plan_features'     => $user->organization?->getPlanFeatures() ?? [],
            'subscription_info' => [
                'status'               => $subscription->status,
                'plan'                 => $subscription->plan,
                'current_period_start' => $subscription->current_period_start?->toIso8601String(),
                'current_period_end'   => null,
                'trial_ends_at'        => $subscription->trial_ends_at?->toIso8601String(),
            ],
        ], 201);
    }

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

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

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

        // sendResetLink always returns a status constant regardless of whether the
        // email exists — this prevents user-enumeration attacks.
        $status = Password::sendResetLink($request->only('email'));

        return response()->json([
            'message' => 'If an account with that email exists, a reset link has been sent.',
        ]);
    }

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

        $status = Password::reset(
            $request->only('email', 'password', 'password_confirmation', 'token'),
            function (User $user, string $password) {
                $user->forceFill(['password' => Hash::make($password)])->save();
                // Revoke all existing API tokens so old sessions are invalidated
                $user->tokens()->delete();
            }
        );

        if ($status === Password::PASSWORD_RESET) {
            return response()->json(['message' => 'Password reset successfully. You can now log in.']);
        }

        return response()->json([
            'message' => match ($status) {
                Password::INVALID_TOKEN => 'This reset link is invalid or has already been used.',
                Password::INVALID_USER  => 'No account found with that email address.',
                default                 => 'Unable to reset password. Please request a new reset link.',
            },
        ], 422);
    }

    public function user(Request $request)
    {
        $user = $request->user()->load(['roles', 'organization.subscription']);

        // Lazily expire any overdue subscription before we report the status
        $subscription = $user->organization?->subscription;
        if ($subscription) {
            $subscription->expireIfNeeded();
        }

        $planFeatures   = $user->organization?->getPlanFeatures() ?? [];
        $subscriptionInfo = null;
        if ($subscription) {
            $subscriptionInfo = [
                'status'              => $subscription->status,
                'plan'                => $subscription->plan,
                'current_period_end'  => $subscription->current_period_end?->toIso8601String(),
                'trial_ends_at'       => $subscription->trial_ends_at?->toIso8601String(),
            ];
        }

        return response()->json([
            'user'              => $user,
            'permissions'       => $user->getAllPermissions()->pluck('name'),
            'email_verified'    => $user->hasVerifiedEmail(),
            'plan_features'     => $planFeatures,
            'org_features'      => $user->organization?->getOrgFeatures() ?? [],
            'subscription_info' => $subscriptionInfo,
        ]);
    }
}
