<?php

namespace App\Http\Controllers\Base;

use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Services\Contracts\ServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Yajra\DataTables\Facades\DataTables;

abstract class BaseController extends Controller
{
    use HasRoleViews;

    /**
     * The service instance
     */
    protected ServiceInterface $service;

    /**
     * The module name for views and routes (e.g., 'rfq', 'quotation', 'customer')
     */
    protected string $module;

    /**
     * The display name for messages (e.g., 'RFQ', 'Quotation', 'Customer')
     */
    protected string $displayName;

    /**
     * Relations to eager load for index/list
     */
    protected array $listRelations = [];

    /**
     * Relations to eager load for show/edit
     */
    protected array $showRelations = [];

    /**
     * Constructor
     */
    public function __construct(ServiceInterface $service)
    {
        $this->service = $service;
    }

    /**
     * Display a listing of the resource
     */
    public function index()
    {
        return $this->roleView("{$this->module}.index");
    }

    /**
     * Get data for DataTables
     */
    public function list()
    {
        $query = $this->service->getForDataTable();

        if (!empty($this->listRelations)) {
            $query = $query->with($this->listRelations);
        }

        return DataTables::of($query)
            ->addIndexColumn()
            ->addColumn('action', function ($row) {
                return $this->getActionButtons($row);
            })
            ->rawColumns(['action'])
            ->make(true);
    }

    /**
     * Generate action buttons for DataTable
     */
    protected function getActionButtons($row): string
    {
        $editRoute = route($this->resolveRoute("{$this->module}.edit"), $row->id);
        $showRoute = route($this->resolveRoute("{$this->module}.show"), $row->id);

        return '
            <a href="' . $showRoute . '" class="btn btn-info btn-sm" title="View">
                <i class="fas fa-eye"></i>
            </a>
            <a href="' . $editRoute . '" class="btn btn-primary btn-sm" title="Edit">
                <i class="fas fa-edit"></i>
            </a>
            <button class="btn btn-danger btn-sm delete-btn" data-id="' . $row->id . '" title="Delete">
                <i class="fas fa-trash"></i>
            </button>
        ';
    }

    /**
     * Show the form for creating a new resource
     */
    public function create()
    {
        $data = $this->getCreateData();
        return $this->roleView("{$this->module}.create", $data);
    }

    /**
     * Get additional data for create form
     */
    protected function getCreateData(): array
    {
        return [];
    }

    /**
     * Store a newly created resource
     */
    public function store(Request $request)
    {
        $validated = $this->validateStore($request);

        try {
            $record = $this->service->create($validated);

            $this->logAction('created', $record);

            return $this->redirectToRoute("{$this->module}.index")
                ->with('success', "{$this->displayName} created successfully.");
        } catch (\Exception $e) {
            Log::error("{$this->displayName} creation failed: " . $e->getMessage());

            return back()
                ->withInput()
                ->with('error', "Failed to create {$this->displayName}. Please try again.");
        }
    }

    /**
     * Validate store request
     */
    protected function validateStore(Request $request): array
    {
        return $request->validate($this->getValidationRules());
    }

    /**
     * Get validation rules for store/update
     */
    protected function getValidationRules(): array
    {
        return [];
    }

    /**
     * Display the specified resource
     */
    public function show(int $id)
    {
        $record = $this->service->findByIdWith($id, $this->showRelations);

        if (!$record) {
            return $this->redirectToRoute("{$this->module}.index")
                ->with('error', "{$this->displayName} not found.");
        }

        $data = $this->getShowData($record);
        $data[$this->getRecordVariableName()] = $record;

        return $this->roleView("{$this->module}.show", $data);
    }

    /**
     * Get additional data for show view
     */
    protected function getShowData($record): array
    {
        return [];
    }

    /**
     * Show the form for editing the specified resource
     */
    public function edit(int $id)
    {
        $record = $this->service->findByIdWith($id, $this->showRelations);

        if (!$record) {
            return $this->redirectToRoute("{$this->module}.index")
                ->with('error', "{$this->displayName} not found.");
        }

        $data = $this->getEditData($record);
        $data[$this->getRecordVariableName()] = $record;

        return $this->roleView("{$this->module}.edit", $data);
    }

    /**
     * Get additional data for edit form
     */
    protected function getEditData($record): array
    {
        return $this->getCreateData();
    }

    /**
     * Update the specified resource
     */
    public function update(Request $request, int $id)
    {
        $validated = $this->validateUpdate($request, $id);

        try {
            $record = $this->service->update($id, $validated);

            $this->logAction('updated', $record);

            return $this->redirectToRoute("{$this->module}.index")
                ->with('success', "{$this->displayName} updated successfully.");
        } catch (\Exception $e) {
            Log::error("{$this->displayName} update failed: " . $e->getMessage());

            return back()
                ->withInput()
                ->with('error', "Failed to update {$this->displayName}. Please try again.");
        }
    }

    /**
     * Validate update request
     */
    protected function validateUpdate(Request $request, int $id): array
    {
        return $this->validateStore($request);
    }

    /**
     * Remove the specified resource
     */
    public function destroy(int $id): JsonResponse
    {
        try {
            $record = $this->service->findById($id);

            if (!$record) {
                return response()->json([
                    'success' => false,
                    'message' => "{$this->displayName} not found."
                ], 404);
            }

            $this->service->delete($id);

            $this->logAction('deleted', $record);

            return response()->json([
                'success' => true,
                'message' => "{$this->displayName} deleted successfully."
            ]);
        } catch (\Exception $e) {
            Log::error("{$this->displayName} deletion failed: " . $e->getMessage());

            return response()->json([
                'success' => false,
                'message' => "Failed to delete {$this->displayName}."
            ], 500);
        }
    }

    /**
     * Get the variable name for the record in views
     */
    protected function getRecordVariableName(): string
    {
        return strtolower($this->module);
    }

    /**
     * Log an action
     */
    protected function logAction(string $action, $record): void
    {
        Log::info("{$this->getLogPrefix()} - {$this->displayName} {$action}", [
            'id' => $record->id ?? null,
            'user_id' => auth()->id(),
        ]);
    }

    /**
     * Return success JSON response
     */
    protected function jsonSuccess(string $message, array $data = []): JsonResponse
    {
        return response()->json(array_merge([
            'success' => true,
            'message' => $message,
        ], $data));
    }

    /**
     * Return error JSON response
     */
    protected function jsonError(string $message, int $status = 400): JsonResponse
    {
        return response()->json([
            'success' => false,
            'message' => $message,
        ], $status);
    }
}
