<?php

namespace App\Http\Controllers;

use App\Models\DigitalMachine;
use App\Models\MachinePayment;
use App\Models\PaymentConfiguration;
use App\Services\DirectorySearchService;
use App\Services\PaymentService;
use App\Services\EmailService;
use App\Http\Requests\StoreDigitalMachineRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

/**
 * DigitalMachineController
 *
 * Handles digital health machine showcase and management.
 * Supports public views and authenticated Health Marketor dashboard.
 *
 * Requirements: 3.1-3.5, 6.1-6.5
 */
class DigitalMachineController extends Controller
{
    protected DirectorySearchService $searchService;
    protected PaymentService $paymentService;
    protected EmailService $emailService;

    public function __construct(
        DirectorySearchService $searchService,
        PaymentService $paymentService,
        EmailService $emailService
    ) {
        $this->searchService = $searchService;
        $this->paymentService = $paymentService;
        $this->emailService = $emailService;
    }

    // =========================================================================
    // PUBLIC METHODS
    // =========================================================================

    /**
     * Display public machine showcase.
     *
     * Requirements: 6.1
     */
    public function index(Request $request)
    {
        $query = (string) ($request->get('q') ?? '');
        $filters = [
            'category'      => $request->get('category') ?: null,
            'brand'         => $request->get('brand') ?: null,
            'price_visible' => $request->get('price_visible') ?: null,
            'price_min'     => $request->get('price_min') ?: null,
            'price_max'     => $request->get('price_max') ?: null,
            'currency'      => $request->get('currency', 'SSP'),
        ];

        $machines = $this->searchService->searchMachines($query, $filters, 12);

        // Preserve all active query params across pagination links
        $machines->appends($request->query());

        // Get filter options (always from full published set)
        $categories = $this->searchService->getCategoriesWithCount();
        $brands     = $this->searchService->getBrandsWithCount();

        // Get featured machines for sidebar
        $featured = $this->searchService->getFeaturedMachines(4);

        return view('machines.index', compact(
            'machines',
            'query',
            'filters',
            'categories',
            'brands',
            'featured'
        ));
    }

    /**
     * Display machine detail page.
     *
     * Requirements: 6.3, 6.4
     */
    public function show(string $slug)
    {
        $machine = DigitalMachine::where('slug', $slug)
            ->published()
            ->firstOrFail();

        // Increment view count
        $machine->incrementViewCount();

        // Get related machines
        $related = DigitalMachine::published()
            ->where('id', '!=', $machine->id)
            ->where(function ($q) use ($machine) {
                $q->where('category', $machine->category)
                    ->orWhere('brand', $machine->brand);
            })
            ->limit(4)
            ->get();

        return view('machines.show', compact('machine', 'related'));
    }

    /**
     * AJAX search for real-time dropdown results.
     * Returns JSON with `results` array containing name, brand, category, slug, url.
     *
     * Requirements: 6.1, 6.2, 6.5, 6.6
     */
    public function ajaxSearch(Request $request)
    {
        $query = $request->get('q', '');

        if (strlen($query) < 2) {
            return response()->json(['results' => []]);
        }

        $machines = DigitalMachine::query()
            ->published()
            ->search($query)
            ->orderByDesc('published_at')
            ->limit(10)
            ->get(['id', 'name', 'slug', 'brand', 'category', 'primary_image', 'images'])
            ->map(fn($machine) => [
                'name'              => $machine->name,
                'brand'             => $machine->brand,
                'category'          => $machine->category,
                'slug'              => $machine->slug,
                'url'               => route('machines.show', $machine->slug),
                'primary_image_url' => $machine->primary_image
                    ? asset('storage/' . $machine->primary_image)
                    : (!empty($machine->images) && is_array($machine->images)
                        ? asset('storage/' . $machine->images[0])
                        : null),
            ]);

        return response()->json(['results' => $machines]);
    }

    /**
     * Real-time search for AJAX requests.
     * Supports ?q=, ?category=, ?brand= query params.
     *
     * Requirements: 6.5
     */
    public function search(Request $request)
    {
        $query    = $request->get('q', '');
        $category = $request->get('category', '');
        $brand    = $request->get('brand', '');

        $machines = DigitalMachine::query()
            ->published()
            ->when(strlen($query) >= 1, fn ($q) => $q->search($query))
            ->when($category, fn ($q) => $q->where('category', $category))
            ->when($brand,    fn ($q) => $q->where('brand', $brand))
            ->orderByDesc('published_at')
            ->limit(12)
            ->get(['id', 'name', 'slug', 'brand', 'model', 'category', 'primary_image', 'images', 'description'])
            ->map(fn ($machine) => [
                'id'          => $machine->id,
                'name'        => $machine->name,
                'slug'        => $machine->slug,
                'brand'       => $machine->brand,
                'model'       => $machine->model,
                'category'    => $machine->category,
                'description' => $machine->description
                    ? \Illuminate\Support\Str::limit($machine->description, 100)
                    : null,
                'primary_image_url' => $machine->primary_image
                    ? asset('storage/' . $machine->primary_image)
                    : (!empty($machine->images) && is_array($machine->images)
                        ? asset('storage/' . $machine->images[0])
                        : null),
                'url'         => route('machines.show', $machine->slug),
            ]);

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

    // =========================================================================
    // HEALTH MARKETOR DASHBOARD METHODS
    // =========================================================================

    /**
     * Display Health Marketor's machine management dashboard.
     *
     * Requirements: 3.5
     */
    public function dashboard(Request $request)
    {
        abort_unless(auth()->user()->can('view machines'), 403);

        $machines = DigitalMachine::where('user_id', auth()->id())
            ->latest()
            ->paginate(10);

        $stats = [
            'total' => DigitalMachine::where('user_id', auth()->id())->count(),
            'active' => DigitalMachine::where('user_id', auth()->id())
                ->where('listing_status', 'published')->count(),
            'pending' => DigitalMachine::where('user_id', auth()->id())
                ->whereIn('listing_status', ['pending_payment', 'pending_approval'])->count(),
            'expired' => DigitalMachine::where('user_id', auth()->id())
                ->where('listing_status', 'expired')->count(),
        ];

        return view('machines.dashboard.index', compact('machines', 'stats'));
    }

    /**
     * Show form to create new machine listing.
     *
     * Requirements: 3.1
     */
    public function create()
    {
        abort_unless(auth()->user()->can('create machines'), 403);

        $categories = DigitalMachine::getCategories();
        $paymentConfig = PaymentConfiguration::getForMachines();

        return view('machines.dashboard.create', compact('categories', 'paymentConfig'));
    }

    /**
     * Store new machine listing.
     *
     * Requirements: 3.1
     */
    public function store(StoreDigitalMachineRequest $request)
    {
        abort_unless(auth()->user()->can('create machines'), 403);

        DB::beginTransaction();
        try {
            $data = $request->validated();
            $data['user_id'] = auth()->id();

            // Guard against duplicate machine name for the same user
            $duplicate = DigitalMachine::where('user_id', auth()->id())
                ->where('name', $request->name)
                ->whereNotIn('listing_status', ['rejected', 'suspended'])
                ->first();

            if ($duplicate) {
                DB::rollBack();
                return back()->withInput()
                    ->withErrors(['name' => 'You already have a listing with this machine name.'])
                    ->with('error', 'Duplicate machine name.');
            }

            // Map flat contact fields from the form into the contact_info JSON column
            $contactInfo = [];
            if ($request->filled('contact_phone')) {
                $contactInfo['phone'] = $request->contact_phone;
            }
            if ($request->filled('contact_email')) {
                $contactInfo['email'] = $request->contact_email;
            }
            if (!empty($contactInfo)) {
                $data['contact_info'] = $contactInfo;
            }
            // Remove the flat fields — they are not model columns
            unset($data['contact_phone'], $data['contact_email']);

            // Normalise price_publishable to boolean
            $data['price_publishable'] = filter_var($request->input('price_publishable', true), FILTER_VALIDATE_BOOLEAN);

            // Handle images upload
            $images = [];
            if ($request->hasFile('images')) {
                foreach ($request->file('images') as $index => $image) {
                    $path = $image->store('machines/images', 'public');
                    $images[] = $path;

                    // First image is always primary
                    if ($index === 0) {
                        $data['primary_image'] = $path;
                    }
                }
            }
            $data['images'] = $images;

            // Handle video clips upload
            $videos = [];
            if ($request->hasFile('video_clips')) {
                foreach ($request->file('video_clips') as $video) {
                    $videos[] = $video->store('machines/videos', 'public');
                }
            }
            $data['video_clips'] = $videos;

            // Generate unique slug
            $data['slug'] = DigitalMachine::generateUniqueSlug($request->name);

            // Get payment configuration
            $paymentConfig = PaymentConfiguration::getForMachines();
            $requiresPayment = $paymentConfig && $paymentConfig->requiresPayment();

            // Set initial status
            $data['listing_status'] = $requiresPayment ? 'pending_payment' : 'pending_approval';
            $data['payment_status'] = $requiresPayment ? 'pending' : 'exempt';

            // Create machine
            $machine = DigitalMachine::create($data);

            DB::commit();

            if ($requiresPayment) {
                return redirect()->route('dashboard.machines.payment', $machine)
                    ->with('info', 'Machine added! Please complete payment to submit for approval.');
            }

            return redirect()->route('dashboard.machines.index')
                ->with('success', 'Machine submitted for approval!');

        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()
                ->with('error', 'Failed to add machine: ' . $e->getMessage());
        }
    }

    /**
     * Show edit form for machine.
     *
     * Requirements: 3.2
     */
    public function edit(DigitalMachine $machine)
    {
        // Authorization check
        abort_unless(
            auth()->user()->can('edit machines') &&
            ($machine->isOwnedBy(auth()->user()) ||
             auth()->user()->hasAnyRole(['Super Manager', 'Manager'])),
            403
        );

        $categories = DigitalMachine::getCategories();

        return view('machines.dashboard.edit', compact('machine', 'categories'));
    }

    /**
     * Update machine details.
     *
     * Requirements: 3.2
     */
    public function update(StoreDigitalMachineRequest $request, DigitalMachine $machine)
    {
        // Authorization
        abort_unless(
            auth()->user()->can('edit machines') &&
            ($machine->isOwnedBy(auth()->user()) ||
             auth()->user()->hasAnyRole(['Super Manager', 'Manager'])),
            403
        );

        DB::beginTransaction();
        try {
            $data = $request->validated();

            // Handle new images upload
            if ($request->hasFile('images')) {
                $images = $machine->images ?? [];
                foreach ($request->file('images') as $index => $image) {
                    $path = $image->store('machines/images', 'public');
                    $images[] = $path;
                    
                    if ($request->primary_image === 'new_' . $index) {
                        $data['primary_image'] = $path;
                    }
                }
                $data['images'] = $images;
            }

            // Handle new video clips
            if ($request->hasFile('video_clips')) {
                $videos = $machine->video_clips ?? [];
                foreach ($request->file('video_clips') as $video) {
                    $videos[] = $video->store('machines/videos', 'public');
                }
                $data['video_clips'] = $videos;
            }

            // Handle image deletion
            if ($request->has('remove_images')) {
                $currentImages = $data['images'] ?? $machine->images ?? [];
                foreach ($request->remove_images as $removeIndex) {
                    if (isset($currentImages[$removeIndex])) {
                        Storage::disk('public')->delete($currentImages[$removeIndex]);
                        unset($currentImages[$removeIndex]);
                    }
                }
                $data['images'] = array_values($currentImages);
            }

            // Remove null values
            $data = array_filter($data, fn($value) => !is_null($value));

            $machine->update($data);

            DB::commit();

            return redirect()->route('dashboard.machines.index')
                ->with('success', 'Machine updated successfully!');

        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()
                ->with('error', 'Update failed: ' . $e->getMessage());
        }
    }

    /**
     * Delete machine listing.
     */
    public function destroy(DigitalMachine $machine)
    {
        abort_unless(
            auth()->user()->can('delete machines') &&
            ($machine->isOwnedBy(auth()->user()) ||
             auth()->user()->hasAnyRole(['Super Manager', 'Manager'])),
            403
        );

        // Delete associated files
        if ($machine->images) {
            foreach ($machine->images as $image) {
                Storage::disk('public')->delete($image);
            }
        }
        if ($machine->video_clips) {
            foreach ($machine->video_clips as $video) {
                Storage::disk('public')->delete($video);
            }
        }

        $machine->delete();

        return redirect()->route('dashboard.machines.index')
            ->with('success', 'Machine deleted successfully.');
    }

    /**
     * Show payment page for machine listing.
     */
    public function payment(DigitalMachine $machine)
    {
        abort_unless($machine->isOwnedBy(auth()->user()), 403);

        $paymentConfig = PaymentConfiguration::getForMachines();

        return view('machines.dashboard.payment', compact('machine', 'paymentConfig'));
    }

    // =========================================================================
    // ADMIN METHODS
    // =========================================================================

    /**
     * Admin: Display all machines grid.
     */
    public function adminIndex(Request $request)
    {
        abort_unless(auth()->user()->can('manage machines'), 403);

        $query = DigitalMachine::with('user')
            ->when($request->status, fn($q, $status) => $q->where('listing_status', $status))
            ->when($request->category, fn($q, $cat) => $q->where('category', $cat))
            ->when($request->search, fn($q, $search) => $q->search($search))
            ->latest();

        $machines = $query->paginate(20);

        $stats = [
            'total' => DigitalMachine::count(),
            'published' => DigitalMachine::where('listing_status', 'published')->count(),
            'pending' => DigitalMachine::where('listing_status', 'pending_approval')->count(),
            'rejected' => DigitalMachine::where('listing_status', 'rejected')->count(),
        ];

        $categories = DigitalMachine::getCategories();

        return view('admin.machines.index', compact('machines', 'stats', 'categories'));
    }

    /**
     * Admin: Approve machine listing.
     *
     * Requirements: 3.5
     */
    public function approve(DigitalMachine $machine)
    {
        abort_unless(auth()->user()->can('approve machines'), 403);

        $machine->approve(auth()->id());

        // Notify the marketor
        if ($this->emailService->isReady() && $machine->user) {
            $this->emailService->sendTemplate(
                $machine->user->email,
                'Your Machine Listing Has Been Approved',
                'emails.machine-approved',
                ['machineName' => $machine->name, 'userName' => $machine->user->name]
            );
        }

        return back()->with('success', 'Machine approved and published.');
    }

    /**
     * Admin: Reject machine listing.
     */
    public function reject(Request $request, DigitalMachine $machine)
    {
        abort_unless(auth()->user()->can('approve machines'), 403);

        $request->validate([
            'rejection_reason' => 'required|string|max:1000',
        ]);

        $machine->reject(auth()->id(), $request->rejection_reason);

        // Notify the marketor
        if ($this->emailService->isReady() && $machine->user) {
            $this->emailService->sendTemplate(
                $machine->user->email,
                'Your Machine Listing Needs Revision',
                'emails.machine-rejected',
                [
                    'machineName' => $machine->name,
                    'userName' => $machine->user->name,
                    'reason' => $request->rejection_reason
                ]
            );
        }

        return back()->with('success', 'Machine rejected.');
    }
}
