<?php

namespace App\Http\Controllers\Opportunity;

use Exception;
use Illuminate\Http\Request;
use App\Constants\ActivityTypes;
use App\Enums\SeveritySystemLog;
use App\Enums\StagesOpportunity;
use App\Services\BitacoraService;
use Illuminate\Support\Facades\DB;
use App\Http\Responses\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Messages\SuccessMessages;
use App\Http\Requests\PaginationRequest;
use App\Http\Resources\PaginacionResource;
use App\Services\Customer\CustomerService;
use App\Services\Opportunity\OpportunityService;
use App\Http\Resources\Opportunity\OpportunityResource;
use App\Http\Requests\Opportunity\AddOpportunityRequest;
use App\Http\Requests\Opportunity\UpdateOpportunityRequest;
use App\Services\Conversation\ConversationService;
use App\Services\Opportunity\ProcedureOpportunityService;
use App\Services\SystemLogService;

class OpportunityController extends Controller
{
    protected $opportunityService;
    protected $bitacoraService;
    protected $conversationService;
    protected $customerService;
    protected $procedureOpportunityService;
    protected $systemLogService;

    public function __construct(
        OpportunityService $opportunityService,
        BitacoraService $bitacoraService,
        ProcedureOpportunityService $procedureOpportunityService,
        ConversationService $conversationService,
        CustomerService $customerService,
        SystemLogService $systemLogService
    ) {
        $this->opportunityService = $opportunityService;
        $this->bitacoraService = $bitacoraService;
        $this->conversationService = $conversationService;
        $this->customerService = $customerService;
        $this->procedureOpportunityService = $procedureOpportunityService;
        $this->systemLogService = $systemLogService;
    }
    /**
     * @OA\Post(path="/api/opportunity/register", summary="Registrar una nueva oportunidad", description="Registra una nueva oportunidad para un cliente. Verifica si ya existe una oportunidad activa para el cliente.", tags={"Opportunities"},
     *     @OA\RequestBody(required=true, @OA\JsonContent(type="object", required={"customer_id", "description", "stage_id", "user_id", "source_id", "contact_method_id", "customer_references_id", "property_id"},
     *         @OA\Property(property="customer_id", type="integer", example=1, description="ID del cliente"),
     *         @OA\Property(property="description", type="string", example="Descripción de la oportunidad", description="Descripción de la oportunidad"),
     *         @OA\Property(property="stage_id", type="integer", example=1, description="ID de la etapa"),
     *         @OA\Property(property="user_id", type="integer", example=1, description="ID del usuario asignado"),
     *         @OA\Property(property="source_id", type="integer", example=1, description="ID de la fuente"),
     *         @OA\Property(property="contact_method_id", type="integer", example=1, description="ID del método de contacto"),
     *         @OA\Property(property="customer_references_id", type="integer", example=1, description="ID de la referencia del cliente"),
     *         @OA\Property(property="property_id", type="integer", example=1, description="ID de la propiedad")
     *     )),
     *     @OA\Response(response=201, description="Oportunidad creada exitosamente", @OA\JsonContent(@OA\Property(property="status", type="string", example="success"), @OA\Property(property="message", type="string", example="Oportunidad creada con éxito"))),
     *     @OA\Response(response=500, description="Error interno del servidor", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Error interno del servidor")))
     * )
     */
    public function register_new_Opportunity(AddOpportunityRequest $addOpportunityRequest)
    {
        try {
            return DB::transaction(function () use ($addOpportunityRequest) {
                $customer = $this->opportunityService->checkActiveOpportunityForCustomer($addOpportunityRequest->input('customer_id'));
                $opportunity = $this->opportunityService->createOpportunity($customer, $addOpportunityRequest->validated());
                $this->bitacoraService->logActivity(ActivityTypes::OPPORTUNITY_REGISTERED, $opportunity->customer, ['opportunity'=> $opportunity]);
                $this->systemLogService->logActivity('oportunidad','Oportunidad registrada', SeveritySystemLog::info->name, $opportunity);
                return ApiResponse::success(SuccessMessages::CREATE_SUCCESS, new OpportunityResource($opportunity), [], 201);
            });
        } catch (Exception $e) {
            $this->systemLogService->logActivity('oportunidad','Registro de Oportunidad Fallido' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Get(path="/api/opportunity/list-paginated", summary="Listar oportunidades paginadas", description="Obtiene una lista paginada de las oportunidades registradas.", tags={"Opportunities"},
     *     @OA\Parameter(name="page", in="query", description="Número de la página", required=false, @OA\Schema(type="integer", example=1)),
     *     @OA\Parameter(name="itemsPerPage", in="query", description="Cantidad de elementos por página", required=false, @OA\Schema(type="integer", example=10)),
     *     @OA\Response(response=200, description="Lista de oportunidades obtenida exitosamente", @OA\JsonContent(@OA\Property(property="status", type="string", example="success"), @OA\Property(property="pagination", type="object", example={"current_page": 1, "total": 50, "per_page": 10}))),
     *     @OA\Response(response=500, description="Error interno del servidor", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Error interno del servidor")))
     * )
     */
    public function list_oportunity_paginate(PaginationRequest $paginationRequest)
    {
        try {
            $opportunities = $this->opportunityService->getAllOpportunityWithPaginate($paginationRequest);
            $opportunities->data = OpportunityResource::collection($opportunities->getCollection());
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new PaginacionResource($opportunities), [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Get(path="/api/opportunity/get-opportunity/{id}", summary="Obtener una oportunidad", description="Obtiene los detalles de una oportunidad específica mediante su ID.", tags={"Opportunities"},
     *     @OA\Parameter(name="id", in="path", description="ID de la oportunidad", required=true, @OA\Schema(type="integer", example=1)),
     *     @OA\Response(response=200, description="Detalles de la oportunidad obtenidos exitosamente", @OA\JsonContent(@OA\Property(property="status", type="string", example="success"))),
     *     @OA\Response(response=404, description="Oportunidad no encontrada", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Oportunidad no encontrada"))),
     *     @OA\Response(response=500, description="Error interno del servidor", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Error interno del servidor")))
     * )
     */
    public function get_opportunity($id)
    {
        try {
            $opportunity = $this->opportunityService->getOpportunityById($id);
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new OpportunityResource($opportunity), [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Patch(path="/api/opportunity/update/{id}", summary="Actualizar una oportunidad", description="Actualiza los detalles de una oportunidad existente mediante su ID.", tags={"Opportunities"},
     *     @OA\Parameter(name="id", in="path", description="ID de la oportunidad", required=true, @OA\Schema(type="integer", example=1)),
     *     @OA\Response(response=200, description="Oportunidad actualizada exitosamente", @OA\JsonContent(@OA\Property(property="status", type="string", example="success"), @OA\Property(property="message", type="string", example="Oportunidad actualizada con éxito"))),
     *     @OA\Response(response=404, description="Oportunidad no encontrada", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Oportunidad no encontrada"))),
     *     @OA\Response(response=500, description="Error interno del servidor", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Error interno del servidor")))
     * )
     */
    public function update_opportunity($id, UpdateOpportunityRequest $updateOpportunityRequest)
    {
        try {
            return DB::transaction(function () use ($id, $updateOpportunityRequest) {
                $opportunity = $this->opportunityService->updateOpportunity($id, $updateOpportunityRequest->all());
                if ($updateOpportunityRequest->customer) {
                   $customer =  $this->customerService->updateCustomer($opportunity->customer_id, $updateOpportunityRequest->customer);
                    $this->bitacoraService->logActivity(ActivityTypes::OPPORTUNITY_UPDATED, $opportunity->customer,['opportunity'=>$opportunity]);
                    $this->systemLogService->logActivity('oportunidad','Oportunidad actualizada', SeveritySystemLog::info->name, $opportunity);
                    $this->systemLogService->logActivity('cliente','Cliente actualizado', SeveritySystemLog::info->name, $customer);
                }
                return ApiResponse::success(SuccessMessages::UPDATE_SUCCESS, new OpportunityResource($opportunity), [], 200);
            });
        } catch (Exception $e) {
            $this->systemLogService->logActivity('oportunidad','Actualizacion de Oportunidad fallida' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Get(path="/api/opportunity/kanban/{user_id}", summary="Obtener oportunidades en formato kanban", description="Obtiene las oportunidades en formato kanban para un usuario específico.", tags={"Opportunities"},
     *     @OA\Parameter(name="user_id", in="path", description="ID del usuario", required=true, @OA\Schema(type="integer", example=1)),
     *     @OA\Response(response=200, description="Oportunidades en formato kanban obtenidas exitosamente", @OA\JsonContent(@OA\Property(property="status", type="string", example="success"), @OA\Property(property="data", type="array", @OA\Items(type="object", @OA\Property(property="id", type="integer", example=1), @OA\Property(property="description", type="string", example="Oportunidad de venta"), @OA\Property(property="stage", type="string", example="En progreso"), @OA\Property(property="assigned_user", type="string", example="Usuario Asignado"), @OA\Property(property="created_at", type="string", format="date-time", example="2024-07-01T12:00:00Z"))))),
     *     @OA\Response(response=404, description="Oportunidades no encontradas", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="No se encontraron oportunidades para el usuario especificado"))),
     *     @OA\Response(response=500, description="Error interno del servidor", @OA\JsonContent(@OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Error interno del servidor")))
     * )
     */
    public function oportunity_kanban_user($user_id)
    {
        try {
            $opportunitiesKanban = $this->opportunityService->allOportunityKanban($user_id);
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, $opportunitiesKanban, [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }
    /**
     * @OA\Patch(path="/api/opportunity/convert-prospect/{id}", summary="Convertir oportunidad a prospecto", tags={"Opportunities"},
     *     @OA\Parameter(name="id", in="path", required=true, description="ID de la oportunidad"),
     *     @OA\RequestBody(required=true, @OA\JsonContent(type="object", example={"stage_id": 2})),
     *     @OA\Response(response=200, description="Oportunidad convertida con éxito"),
     *     @OA\Response(response=400, description="Error de validación"))
     */
    public function convert_opportunity_prospect($id, Request $updateOpportunityRequest)
    {
        try {
            return DB::transaction(function () use ($id, $updateOpportunityRequest) {
                $opportunityProspect = $this->opportunityService->convertOpportunityProspect($id, $updateOpportunityRequest->all());
                if (!empty($opportunityProspect->customer->conversation_id)) {
                    $this->conversationService->disableConversacionCustomer($opportunityProspect->customer->conversation_id);
                }
                $this->procedureOpportunityService->createbyStage(StagesOpportunity::PROSPECT->value(), $id);
                $this->bitacoraService->logActivity(ActivityTypes::BECAME_PROSPECT, $opportunityProspect->customer, ['opportunity'=>$opportunityProspect]);
                $this->systemLogService->logActivity('oportunidad','Oportunidad paso a Prospecto', SeveritySystemLog::info->name , $opportunityProspect);
                return ApiResponse::success(SuccessMessages::UPDATE_SUCCESS, new OpportunityResource($opportunityProspect), [], 200);
            });
        } catch (Exception $e) {
            $this->systemLogService->logActivity('oportunidad','Cambio de estado de oportunidad fallida' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }
}
