<?php

namespace App\Http\Controllers\Customer;

use App\Http\Resources\Opportunity\OpportunityResource;
use Exception;
use Illuminate\Http\Request;
use App\Constants\ActivityTypes;
use App\Enums\SeveritySystemLog;
use App\Exports\CustomerExport;
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\Http\Resources\Customer\CustomerResource;
use App\Http\Requests\Customer\AddCustomerRequest;
use App\Http\Requests\Customer\EditCustomerRequest;
use App\Http\Resources\Customer\OpportunityPerfilResource;
use App\Http\Resources\Opportunity\ActivityResource;
use App\Http\Resources\Quote\QuoteResource;
use App\Http\Resources\Sales\SaleResource;
use App\Services\Conversation\ConversationService;
use App\Services\Opportunity\ActivityService;
use App\Services\Opportunity\OpportunityService;
use App\Services\SystemLogService;
use App\Services\User\UserService;
use Maatwebsite\Excel\Facades\Excel;

class CustomerController extends Controller
{
    protected $customerService;
    protected $bitacoraService;
    protected $opportunityService;
    protected $conversationService;
    protected $userService;
    protected $activityService;
    protected $systemLogService;

    public function __construct(
        ActivityService $activityService,
        CustomerService $customerService,
        BitacoraService $bitacoraService,
        OpportunityService $opportunityService,
        ConversationService $conversationService,
        UserService $userService,
        SystemLogService $systemLogService
    ) {
        $this->customerService = $customerService;
        $this->bitacoraService = $bitacoraService;
        $this->opportunityService = $opportunityService;
        $this->conversationService = $conversationService;
        $this->userService = $userService;
        $this->activityService = $activityService;
        $this->systemLogService = $systemLogService;
    }
    /**
     * @OA\Get(
     *     path="/api/customer/get-customer/{id}",
     *     summary="Get customer details",
     *     description="Retrieve details of a specific customer by ID",
     *     tags={"Customers"},
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="Customer ID",
     *         required=true,
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Customer details retrieved successfully"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Customer not found"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Internal server error"
     *     )
     * )
     */
    public function get_customer($id)
    {
        try {
            $customer = $this->customerService->getCustomerById($id);
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new CustomerResource($customer), [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Get(
     *     path="/api/customer/perfil/{id}",
     *     summary="Get customer details",
     *     description="Retrieve details of a specific customer by ID",
     *     tags={"Customers"},
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="Customer ID",
     *         required=true,
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Customer details retrieved successfully"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Customer not found"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Internal server error"
     *     )
     * )
     */
    public function get_perfil_customer($id)
    {
        try {
            $customer = $this->customerService->getCustomerById($id);
            $data = [
                'customer' => new CustomerResource($customer),
                'opportunities' => OpportunityPerfilResource::collection($customer->opportunities->sortByDesc('created_at')),
                'quotes' => QuoteResource::collection($customer->quotes),
                'sales' => SaleResource::collection($customer->sales),
                'activities' => ActivityResource::collection($customer->activities->sortByDesc('created_at'))
            ];

            return ApiResponse::success(SuccessMessages::SUCCESSFUL, $data, [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Get(
     *     path="/api/customer/get-customer-phone",
     *     summary="Get customer details by phone",
     *     description="Retrieve details of a specific customer by phone number and country code",
     *     operationId="getCustomerByPhone",
     *     tags={"Customers"},
     *     @OA\Parameter(
     *         name="phone",
     *         in="query",
     *         description="Customer's phone number",
     *         required=true,
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Parameter(
     *         name="country_code",
     *         in="query",
     *         description="Customer's country code",
     *         required=true,
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Customer details retrieved successfully",
     *         @OA\JsonContent(
     *             @OA\Property(property="message", type="string", example="Request was successful"),
     *         )
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Customer not found",
     *         @OA\JsonContent(
     *             @OA\Property(property="message", type="string", example="Customer not found"),
     *         )
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Internal server error",
     *         @OA\JsonContent(
     *             @OA\Property(property="message", type="string", example="An error occurred"),
     *         )
     *     )
     * )
     */

    public function get_customer_by_phone(Request $request)
    {
        try {
            $customer = $this->customerService->getCustomerByPhone($request->query('phone'), $request->query('country_code'));
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new CustomerResource($customer), [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Post(
     *     path="/api/customer/register",
     *     summary="Register a new customer",
     *     description="Register a new customer in the system",
     *     operationId="registerCustomer",
     *     tags={"Customers"},
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="name", type="string", example="John Doe", description="Customer's name"),
     *             @OA\Property(property="phone", type="string", example="77049267", description="Customer's phone number"),
     *             @OA\Property(property="email", type="string", format="email", example="johndoe@example.com", description="Customer's email address"),
     *             @OA\Property(property="gender", type="string", enum={"M", "F", "other"}, example="M", description="Customer's gender"),
     *             @OA\Property(property="ci", type="integer", example=123456789, description="Customer's identification number"),
     *             @OA\Property(property="cod_phone", type="string", example="+591", description="Customer's phone code"),
     *             @OA\Property(property="date_of_birthday", type="string", format="date", example="1990-01-01", description="Customer's date of birth"),
     *             @OA\Property(property="adress", type="string", example="123 Main St", description="Customer's address")
     *         )
     *     ),
     *     @OA\Response(
     *         response=201,
     *         description="Customer created successfully",
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Internal server error"
     *     )
     * )
     */
    public function register_customer(AddCustomerRequest $addCustomerRequest)
    {
        try {
            return DB::transaction(function () use ($addCustomerRequest) {
                $conversation = $this->conversationService->getConversationByPhone($addCustomerRequest->cod_phone . $addCustomerRequest->phone);
                if (!$conversation) {
                    $conversation['phone'] = $addCustomerRequest->cod_phone . $addCustomerRequest->phone;
                    $conversation['thread'] = $addCustomerRequest->thread;
                    $conversation['isCustomer'] = true;
                    $conversation = $this->conversationService->createConversation($conversation);
                }
                $addCustomerRequest->merge(['conversation_id' => $conversation->id]);
                $customer = $this->customerService->createCustomer($addCustomerRequest->all());
                $this->conversationService->checkCustomerRegister($customer->conversation_id);
                if (!$addCustomerRequest->user_id) {
                    //Todo: cambiar cuando se tenga mas de un asesor
                    // $addCustomerRequest->merge(['user_id' => $this->userService->selectAsesor()]);
                    $addCustomerRequest->merge(['user_id' => 3]);
                }
                $opportunity = $this->opportunityService->createOpportunity($customer, $addCustomerRequest->all());
                $this->bitacoraService->logActivity(ActivityTypes::CUSTOMER_REGISTERED, $customer, ['customer' => $customer]);
                $this->systemLogService->logActivity('cliente','Cliente registrado', SeveritySystemLog::info->name, $customer);
                $this->systemLogService->logActivity('oportunidad','Oportunidad registrada', SeveritySystemLog::info->name, $opportunity);

                return ApiResponse::success(SuccessMessages::CREATE_SUCCESS, ['customer' => new CustomerResource($customer), 'opportunity' => new OpportunityResource($opportunity)], [], 201);
            });
        } catch (Exception $e) {
            $this->systemLogService->logActivity('cliente','Registro de Cliente fallido' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    public function register_customer_like_prospect(AddCustomerRequest $addCustomerRequest)
    {
        try {
            return DB::transaction(function () use ($addCustomerRequest) {
                $conversation = $this->conversationService->getConversationByPhone($addCustomerRequest->cod_phone . $addCustomerRequest->phone);
                if (!$conversation) {
                    $conversation['phone'] = $addCustomerRequest->cod_phone . $addCustomerRequest->phone;
                    $conversation['thread'] = $addCustomerRequest->thread;
                    $conversation['isCustomer'] = true;
                    $conversation = $this->conversationService->createConversation($conversation);
                }
                $addCustomerRequest->merge(['conversation_id' => $conversation->id]);
                $customer = $this->customerService->createCustomer($addCustomerRequest->all());
                $this->conversationService->checkCustomerRegister($customer->conversation_id);
                if (!$addCustomerRequest->user_id) {
                    //Todo: cambiar cuando se tenga mas de un asesor
                    // $addCustomerRequest->merge(['user_id' => $this->userService->selectAsesor()]);
                    $addCustomerRequest->merge(['user_id' => 3]);
                }
                $opportunity = $this->opportunityService->createOpportunity($customer, $addCustomerRequest->all());
                $opportunityProspect = $this->opportunityService->convertOpportunityProspect($opportunity->id, $addCustomerRequest->all());
                $activity = $this->activityService->createActivity([
                    'title' => 'Seguimiento',
                    'description' => 'Nuevo Cliente resgistrado empezar con el Seguimiento',
                    'type_activity_id' => '4',
                    'opportunity_id' => $opportunity->id,
                    'assigned_to' => 3,
                    'scheduled_at' => now(),
                ]);
                $this->bitacoraService->logActivity(ActivityTypes::CUSTOMER_REGISTERED, $customer, ['customer' => $customer]);
                $this->systemLogService->logActivity('cliente','Cliente registrado', SeveritySystemLog::info->name, $customer);
                $this->systemLogService->logActivity('oportunidad','Oportunidad registrada', SeveritySystemLog::info->name, $opportunity);
                $this->systemLogService->logActivity('oportunidad','Oportunidad paso a Prospecto', SeveritySystemLog::info->name, $opportunity);
                $this->systemLogService->logActivity('actividad','Actividad registrada', SeveritySystemLog::info->name, $activity);
                return ApiResponse::success(SuccessMessages::CREATE_SUCCESS, ['customer' => new CustomerResource($customer), 'opportunity' => new OpportunityResource($opportunity)], [], 201);
            });
        } catch (Exception $e) {
            $this->systemLogService->logActivity('cliente','Registro de Cliente fallido' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\Put(
     *     path="/api/customer/update/{id}",
     *     summary="Update an existing customer",
     *     description="Update customer information",
     *     operationId="updateCustomer",
     *     tags={"Customers"},
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="ID of the customer to update",
     *         required=true,
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="name", type="string", example="John Doe", description="Customer's name"),
     *             @OA\Property(property="phone", type="string", example="77049267", description="Customer's phone number"),
     *             @OA\Property(property="email", type="string", format="email", example="johndoe@example.com", description="Customer's email address"),
     *             @OA\Property(property="gender", type="string", enum={"M", "F", "other"}, example="M", description="Customer's gender"),
     *             @OA\Property(property="ci", type="integer", example=123456789, description="Customer's identification number"),
     *             @OA\Property(property="cod_phone", type="string", example="+591", description="Customer's phone code"),
     *             @OA\Property(property="date_of_birthday", type="string", format="date", example="1990-01-01", description="Customer's date of birth"),
     *             @OA\Property(property="profile_image", type="string", format="binary", description="Customer's profile image"),
     *             @OA\Property(property="workplace", type="string", example="123 Main St", description="Customer's workplace"),
     *             @OA\Property(property="thread", type="string", example="Important customer", description="Additional information about the customer"),
     *             @OA\Property(property="source_id", type="integer", example=1, description="Source ID related to the customer"),
     *             @OA\Property(property="contact_method_id", type="integer", example=2, description="Contact method ID related to the customer"),
     *             @OA\Property(property="customer_references_id", type="integer", example=3, description="Reference ID related to the customer"),
     *             @OA\Property(property="entity_status", type="string", enum={"active", "inactive"}, example="active", description="Status of the customer")
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Customer updated successfully",
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Customer not found"
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Internal server error"
     *     )
     * )
     */
    public function update_customer($id, EditCustomerRequest $editCustomerRequest)
    {
        try {
            return DB::transaction(function () use ($id, $editCustomerRequest) {
                $customer = $this->customerService->updateCustomer($id, $editCustomerRequest->validated());
                $this->bitacoraService->logActivity(ActivityTypes::CUSTOMER_UPDATED, $customer, ['customer' => $customer]);
                $this->systemLogService->logActivity('cliente','Customer actualizado', SeveritySystemLog::info->name, $customer);
                return ApiResponse::success(SuccessMessages::UPDATE_SUCCESS, new CustomerResource($customer), [], 200);
            });
        } catch (Exception $e) {
            $this->systemLogService->logActivity('cliente','Actualización del cliente fallida' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }
    /**
     * @OA\Get(
     *     path="/api/customer/list-paginated",
     *     summary="List Customer with pagination",
     *     tags={"Customers"},
     *     @OA\Parameter(
     *         name="search",
     *         in="query",
     *         description="Search query",
     *         required=false,
     *         @OA\Schema(type="string", maxLength=255)
     *     ),
     *     @OA\Parameter(
     *         name="itemsPerPage",
     *         in="query",
     *         description="Items per page",
     *         required=true,
     *         @OA\Schema(type="integer", minimum=1)
     *     ),
     *     @OA\Parameter(
     *         name="page",
     *         in="query",
     *         description="Page number",
     *         required=true,
     *         @OA\Schema(type="integer", minimum=1)
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=500, description="Internal server error")
     * )
     */
    public function list_customer_paginate(PaginationRequest $paginationRequest)
    {
        try {
            $customers = $this->customerService->getAllCustomerWithPaginate($paginationRequest);
            $customers->data = CustomerResource::collection($customers->getCollection());
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new PaginacionResource($customers), [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    public function customer_export()
    {
        try {
            $customers = $this->customerService->getAllCustomers();
            $this->systemLogService->logActivity('Exportar','Clientes Exportados', SeveritySystemLog::info->name);
            return Excel::download(  new CustomerExport($customers),
            'customers.xlsx',
            \Maatwebsite\Excel\Excel::XLSX);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }
}
