<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;

/**
 * Base Controller
 * 
 * Provides common functionality and PSR-12 compliant structure
 * for all application controllers.
 */
abstract class BaseController extends Controller
{
    /**
     * Validate request data with comprehensive error handling
     *
     * @param Request $request
     * @param array $rules
     * @param array $messages
     * @return array
     * @throws ValidationException
     */
    protected function validateRequest(Request $request, array $rules, array $messages = []): array
    {
        $validator = Validator::make($request->all(), $rules, $messages);

        if ($validator->fails()) {
            $this->logValidationError($request, $validator->errors());
            throw new ValidationException($validator);
        }

        return $validator->validated();
    }

    /**
     * Create standardized JSON response
     *
     * @param mixed $data
     * @param string $message
     * @param int $statusCode
     * @param array $meta
     * @return JsonResponse
     */
    protected function jsonResponse(
        mixed $data = null,
        string $message = 'Success',
        int $statusCode = Response::HTTP_OK,
        array $meta = []
    ): JsonResponse {
        $response = [
            'success' => $statusCode < 400,
            'message' => $message,
            'data' => $data,
        ];

        if (!empty($meta)) {
            $response['meta'] = $meta;
        }

        return response()->json($response, $statusCode);
    }

    /**
     * Create error response
     *
     * @param string $message
     * @param int $statusCode
     * @param array $errors
     * @return JsonResponse
     */
    protected function errorResponse(
        string $message = 'An error occurred',
        int $statusCode = Response::HTTP_INTERNAL_SERVER_ERROR,
        array $errors = []
    ): JsonResponse {
        $response = [
            'success' => false,
            'message' => $message,
        ];

        if (!empty($errors)) {
            $response['errors'] = $errors;
        }

        return response()->json($response, $statusCode);
    }

    /**
     * Log validation errors
     *
     * @param Request $request
     * @param mixed $errors
     * @return void
     */
    protected function logValidationError(Request $request, mixed $errors): void
    {
        Log::warning('Validation failed', [
            'url' => $request->fullUrl(),
            'method' => $request->method(),
            'ip' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'errors' => $errors,
            'input' => $this->sanitizeLogData($request->all()),
        ]);
    }

    /**
     * Log security events
     *
     * @param string $event
     * @param Request $request
     * @param array $context
     * @return void
     */
    protected function logSecurityEvent(string $event, Request $request, array $context = []): void
    {
        Log::warning('Security event: ' . $event, array_merge([
            'url' => $request->fullUrl(),
            'method' => $request->method(),
            'ip' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'user_id' => auth()->id(),
        ], $context));
    }

    /**
     * Sanitize data for logging (remove sensitive information)
     *
     * @param array $data
     * @return array
     */
    protected function sanitizeLogData(array $data): array
    {
        $sensitiveFields = [
            'password',
            'password_confirmation',
            'api_token',
            'license_key',
            'purchase_code',
            'credit_card',
            'ssn',
        ];

        foreach ($sensitiveFields as $field) {
            if (isset($data[$field])) {
                $data[$field] = '[REDACTED]';
            }
        }

        return $data;
    }

    /**
     * Handle exceptions with proper logging and response
     *
     * @param \Exception $exception
     * @param Request $request
     * @param string $context
     * @return JsonResponse
     */
    protected function handleException(\Exception $exception, Request $request, string $context = ''): JsonResponse
    {
        $message = 'An unexpected error occurred';
        $statusCode = Response::HTTP_INTERNAL_SERVER_ERROR;

        if ($exception instanceof ValidationException) {
            $message = 'Validation failed';
            $statusCode = Response::HTTP_UNPROCESSABLE_ENTITY;
        }

        Log::error('Controller exception: ' . $context, [
            'exception' => $exception->getMessage(),
            'file' => $exception->getFile(),
            'line' => $exception->getLine(),
            'url' => $request->fullUrl(),
            'method' => $request->method(),
            'ip' => $request->ip(),
            'user_id' => auth()->id(),
        ]);

        return $this->errorResponse($message, $statusCode);
    }

    /**
     * Check if user has permission
     *
     * @param string $permission
     * @return bool
     */
    protected function hasPermission(string $permission): bool
    {
        return auth()->check() && auth()->user()->can($permission);
    }

    /**
     * Require permission or abort
     *
     * @param string $permission
     * @return void
     */
    protected function requirePermission(string $permission): void
    {
        if (!$this->hasPermission($permission)) {
            abort(Response::HTTP_FORBIDDEN, 'Insufficient permissions');
        }
    }

    /**
     * Get pagination metadata
     *
     * @param mixed $paginator
     * @return array
     */
    protected function getPaginationMeta($paginator): array
    {
        return [
            'current_page' => $paginator->currentPage(),
            'per_page' => $paginator->perPage(),
            'total' => $paginator->total(),
            'last_page' => $paginator->lastPage(),
            'from' => $paginator->firstItem(),
            'to' => $paginator->lastItem(),
        ];
    }
}
