<?php

namespace App\Http\Controllers\Sales;

use Exception;
use Illuminate\Http\Request;
use App\Enums\PropertyStatus;
use App\Constants\ActivityTypes;
use App\Enums\SalesType;
use App\Enums\SeveritySystemLog;
use App\Exports\SaleExport;
use App\Services\BitacoraService;
use App\Services\Sale\SaleService;
use Illuminate\Support\Facades\DB;
use App\Http\Responses\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Messages\ErrorMessages;
use App\Http\Messages\SuccessMessages;
use App\Http\Requests\PaginationRequest;
use App\Http\Resources\PaginacionResource;
use App\Http\Resources\Sales\SaleResource;
use App\Services\Property\PropertyService;
use App\Http\Requests\Sales\AddSalesRequest;
use App\Http\Requests\Sales\UpdateSalesRequest;
use App\Services\Opportunity\OpportunityService;
use App\Services\Opportunity\ProcedureOpportunityService;
use App\Services\SystemLogService;
use Maatwebsite\Excel\Facades\Excel;

class SalesController extends Controller
{
    protected $saleService;
    protected $procedureOpportunityService;
    protected $opportunityService;
    protected $propertiesService;
    protected $bitacoraService;
    protected $systemLogService;

    public function __construct(
        SaleService $saleService,
        ProcedureOpportunityService $procedureOpportunityService,
        OpportunityService $opportunityService,
        PropertyService $propertiesService,
        BitacoraService $bitacoraService,
        SystemLogService $systemLogService
    ) {
        $this->saleService = $saleService;
        $this->procedureOpportunityService = $procedureOpportunityService;
        $this->opportunityService = $opportunityService;
        $this->propertiesService = $propertiesService;
        $this->bitacoraService = $bitacoraService;
        $this->systemLogService = $systemLogService;
    }

    /**
     * @OA\Post(
     *     path="/api/sale/changeStage",
     *     summary="Register to Venta",
     *     tags={"Sales"},
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             @OA\Property(property="nit", type="string", maxLength=255 , example="1234567"),
     *             @OA\Property(property="social_reason", type="string", example= "melanie"),
     *             @OA\Property(property="opportunity_id", example= "1"),
     *             @OA\Property(property="property_id", example= "1"),
     *             @OA\Property(property="stage_id", example= "3"),     *
     *             @OA\Property(property="payment_method", type="string", enum={"DIRECTCREDIT", "CASH", "BANKCREDIT"}, example="CASH"),
     *             @OA\Property(property="amount", example= "100000"),
     *             @OA\Property(property="initial_fee", example= "100000"),
     *             @OA\Property(property="is_payment_initial_fee", type="boolean",  example=true),
     *             @OA\Property(property="delivery_date", example= "2024-09-27 18:52:52"),
     *             @OA\Property(property="differs_initial_fee", type="array", @OA\Items(type="object", @OA\Property(property="date", type="string", example="2023-02-10", description="Fecha del diferido de la cuota inicial"), @OA\Property(property="amount", type="number", format="float", example=500, description="Monto del diferido"))),
     *             @OA\Property(property="differs_balance", type="array", @OA\Items(type="object", @OA\Property(property="date", type="string", example="2023-03-10", description="Fecha del diferido del saldo"), @OA\Property(property="amount", type="number", format="float", example=5000, description="Monto del diferido"))),
     *             @OA\Property(property="properties", type="array", @OA\Items(type="object", @OA\Property(property="property_id", type="integer", example=1, description="ID de la propiedad"), @OA\Property(property="price", type="integer", example=500000, description="Precio de la propiedad"))),
     *         )
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=400, description="Invalid request")
     * )
     */

    public function register_changeStage(AddSalesRequest $request)
    {
        try {
            //todo: quitar el properties_id dentro
            $sales = DB::transaction(function () use ($request) {
                // $this->procedureOpportunityService->verifByOpportunityByStage($request->input('stage_id') -1, $request->input('opportunity_id'));
                foreach ($request->input('properties') as $property) {
                    $this->propertiesService->isAvailableProperty($property['property_id']);
                }
                $sales = $this->saleService->createSales($request->all());
                $this->procedureOpportunityService->createbyStage($request->input('stage_id'), $request->input('opportunity_id'));
                $opportunity =  $this->opportunityService->changeStatus($request->input('opportunity_id'), $request->input('stage_id'));
                $properties = $request->input('properties');
                $this->bitacoraService->logActivity(ActivityTypes::SALE_REGISTERED, $sales->opportunity->customer, ['sales' => $sales]);
                foreach ($properties as $property) {
                  $propertydata =   $this->propertiesService->changeStatus($property['property_id'], PropertyStatus::PRESALE->value); // Array access
                    $this->systemLogService->logActivity('propiedad','Propiedad Reservada', SeveritySystemLog::info->name, $propertydata);
                }
                $this->systemLogService->logActivity('venta','Venta registrada', SeveritySystemLog::info->name,$sales);
                $this->systemLogService->logActivity('procedimiento','Procedimientos añadidos a la oportunidad', SeveritySystemLog::info->name);
                $this->systemLogService->logActivity('oportunidad','Oportunidad paso a Venta', SeveritySystemLog::info->name, $opportunity);

                return $sales;
            });
            return ApiResponse::success(SuccessMessages::CREATE_SUCCESS, new SaleResource($sales), [], 201);
        } catch (\Exception $e) {
            $this->systemLogService->logActivity('venta','Registro de venta fallido' , SeveritySystemLog::error->name);
            $this->systemLogService->logActivity('oportunidad','Cambio de estado de oportunidad fallida' , SeveritySystemLog::error->name);

            return ApiResponse::error(ErrorMessages::BAD_REQUEST, $e->getMessage(), [], $e->getCode());
        }
    }

    /**
     * @OA\Post(
     *     path="/api/sale",
     *     summary="Register to Venta",
     *     tags={"Sales"},
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             @OA\Property(property="nit", type="string", maxLength=255 , example="1234567"),
     *             @OA\Property(property="social_reason", type="string", example= "melanie"),
     *             @OA\Property(property="opportunity_id", example= "1"),
     *             @OA\Property(property="property_id", example= "1"),
     *             @OA\Property(property="stage_id", example= "3"),     *
     *             @OA\Property(property="payment_method", type="string", enum={"DIRECTCREDIT", "CASH", "BANKCREDIT"}, example="CASH"),
     *             @OA\Property(property="amount", example= "100000"),
     *             @OA\Property(property="initial_fee", example= "100000"),
     *             @OA\Property(property="is_payment_initial_fee", type="boolean",  example=true),
     *             @OA\Property(property="delivery_date", example= "2024-09-27 18:52:52"),
     *             @OA\Property(property="differs_initial_fee", type="array", @OA\Items(type="object", @OA\Property(property="date", type="string", example="2023-02-10", description="Fecha del diferido de la cuota inicial"), @OA\Property(property="amount", type="number", format="float", example=500, description="Monto del diferido"))),
     *             @OA\Property(property="differs_balance", type="array", @OA\Items(type="object", @OA\Property(property="date", type="string", example="2023-03-10", description="Fecha del diferido del saldo"), @OA\Property(property="amount", type="number", format="float", example=5000, description="Monto del diferido"))),
     *             @OA\Property(property="properties", type="array", @OA\Items(type="object", @OA\Property(property="property_id", type="integer", example=1, description="ID de la propiedad"), @OA\Property(property="price", type="integer", example=500000, description="Precio de la propiedad"))),
     *         )
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=400, description="Invalid request")
     * )
     */

    public function register(AddSalesRequest $request)
    {
        try {
            $sales = DB::transaction(function () use ($request) {
                foreach ($request->input('properties') as $property) {
                    $this->propertiesService->isAvailableProperty($property['property_id']);
                }
                $sales = $this->saleService->createSales($request->all());
                $this->bitacoraService->logActivity(ActivityTypes::SALE_REGISTERED, $sales->opportunity->customer, ['sales' => $sales]);
                $this->systemLogService->logActivity('venta','Venta registrada', SeveritySystemLog::info->name,$sales);
                $properties = $request->input('properties');
                foreach ($properties as $property) {
                    $propertydata = $this->propertiesService->changeStatus($property['property_id'], PropertyStatus::PRESALE->value); // Array access
                    $this->systemLogService->logActivity('propiedad','Propiedad Reservada', SeveritySystemLog::info->name, $propertydata);
                }
                return $sales;
            });
            return ApiResponse::success(SuccessMessages::CREATE_SUCCESS, new SaleResource($sales), [], 201);
        } catch (\Exception $e) {
            $this->systemLogService->logActivity('venta','Registro de venta Fallida' , SeveritySystemLog::error->name);
            return ApiResponse::error(ErrorMessages::BAD_REQUEST, $e->getMessage(), [], $e->getCode());
        }
    }

    /**
     * @OA\PATCH(
     *     path="/api/sale/{id}/status",
     *     summary="Change Status to Sales",
     *     tags={"Sales"},
     *   @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="ID of the sale",
     *         required=true,
     *         @OA\Schema(
     *             type="integer",
     *             format="int64"
     *         )
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             required={"status"},
     *             @OA\Property(property="status", type="string", enum={"PRESALE", "SALE", "DELIVERY"})
     *         )
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=422, description="Unprocessable Entity"),
     *     @OA\Response(response=400, description="Invalid request"),
     *     @OA\Response(response=500, description="Internal server error")
     * )
     */

    public function change_status(Request $statusrequest, $id)
    {
        try {
            $sale = $this->saleService->changeStatus($id, $statusrequest->input('status'));
            $sale = $this->saleService->getSalebyId($id);
            $this->bitacoraService->logActivity(ActivityTypes::SALE_UPDATED, $sale->opportunity->customer, ['sales' => $sale]);
            $this->systemLogService->logActivity('venta','Venta cambio de estado a ' . $sale->status , SeveritySystemLog::info->name,$sale);
            return ApiResponse::success(SuccessMessages::UPDATE_SUCCESS, $sale, [], 200);
        } catch (\Exception $e) {
            $this->systemLogService->logActivity('venta','Cambio de estado de venta Fallido' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], 500);
        }
    }

    /**
     * @OA\Patch(
     *     path="/api/sale/{id}",
     *     summary="actualizar la Venta",
     *     tags={"Sales"},
     *   @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="ID of the sale",
     *         required=true,
     *         @OA\Schema(
     *             type="integer",
     *             format="int64"
     *         )
     *     ),
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\JsonContent(
     *             @OA\Property(property="nit", type="string", maxLength=255 , example="1234567"),
     *             @OA\Property(property="social_reason", type="string", example= "melanie"),
     *             @OA\Property(property="payment_method", type="string", enum={"DIRECTCREDIT", "CASH", "BANKCREDIT"}, example="CASH"),
     *             @OA\Property(property="amount", example= "100000"),
     *             @OA\Property(property="delivery_date", example= "2024-09-27 18:52:52"),
     *         )
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=400, description="Invalid request")
     * )
     */

    public function update($id, UpdateSalesRequest $request)
    {
        try {
            $project = $this->saleService->updateSale($id, $request->all());
            $sale = $this->saleService->getSalebyId($id);
            $this->bitacoraService->logActivity(ActivityTypes::SALE_UPDATED, $sale->opportunity->customer, ['sales' => $sale]);
            $this->systemLogService->logActivity('venta','Venta actualizada' , SeveritySystemLog::info->name, $sale);
            return ApiResponse::success(SuccessMessages::CREATE_SUCCESS, new SaleResource($project), [], 201);
        } catch (\Exception $e) {
            $this->systemLogService->logActivity('venta','Actualización de venta fallida' , SeveritySystemLog::error->name);
            return ApiResponse::error(ErrorMessages::BAD_REQUEST, $e->getMessage(), [], $e->getCode());
        }
    }

    /**
     * @OA\Get(
     *     path="/api/sale/{id}",
     *     summary="Get venta by ID",
     *     tags={"Sales"},
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="ID of the sale",
     *         required=true,
     *         @OA\Schema(
     *             type="integer",
     *             format="int64"
     *         )
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=404, description="Customer not found"),
     *     @OA\Response(response=500, description="Internal server error"),
     * )
     */

    public function get($id)
    {
        try {
            $activity = $this->saleService->getSalebyId($id);
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new SaleResource($activity), [], 200);
        } catch (\Exception $e) {
            return ApiResponse::error(ErrorMessages::BAD_REQUEST, $e->getMessage(), [], $e->getCode());
        }
    }

    /**
     * @OA\Get(
     *     path="/api/sale/opportunity/{id}",
     *     summary="Get venta by ID de la oportunidad",
     *     tags={"Sales"},
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="ID of the oppotunidad",
     *         required=true,
     *         @OA\Schema(
     *             type="integer",
     *             format="int64"
     *         )
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=404, description="Customer not found"),
     *     @OA\Response(response=500, description="Internal server error"),
     * )
     */

    public function get_by_opportunity($id)
    {
        try {
            $activity = $this->saleService->getSalebyOpportunityId($id);
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new SaleResource($activity), [], 200);
        } catch (\Exception $e) {
            return ApiResponse::error(ErrorMessages::BAD_REQUEST, $e->getMessage(), [], $e->getCode());
        }
    }

    /**
     * @OA\Get(
     *     path="/api/sales/list-paginated",
     *     summary="Listar ventas paginadas",
     *     tags={"Sales"},
     *     @OA\Parameter(name="search", in="query", description="Buscar ventas", required=false, @OA\Schema(type="string", maxLength=255)),
     *     @OA\Parameter(name="itemsPerPage", in="query", description="Elementos por página", required=true, @OA\Schema(type="integer", minimum=1)),
     *     @OA\Parameter(name="page", in="query", description="Número de página", required=true, @OA\Schema(type="integer", minimum=1)),
     *     @OA\Response(response=200, description="Ventas paginadas"),
     *     @OA\Response(response=400, description="Datos inválidos", @OA\JsonContent(type="object", @OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Datos inválidos"))),
     *     @OA\Response(response=500, description="Error del servidor", @OA\JsonContent(type="object", @OA\Property(property="status", type="string", example="error"), @OA\Property(property="message", type="string", example="Error interno del servidor")))
     * )
     */

    public function list_sales_paginate(PaginationRequest $paginationRequest)
    {
        try {
            $sales = $this->saleService->getAllsalepagination($paginationRequest);
            $sales->data = SaleResource::collection($sales->getCollection());
            return ApiResponse::success(SuccessMessages::SUCCESSFUL, new PaginacionResource($sales), [], 200);
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }

    /**
     * @OA\PATCH(
     *     path="/api/sale/{id}/discard",
     *     summary="Change Status to Sales",
     *     tags={"Sales"},
     *   @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="ID of the sale",
     *         required=true,
     *         @OA\Schema(
     *             type="integer",
     *             format="int64"
     *         )
     *     ),

     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=422, description="Unprocessable Entity"),
     *     @OA\Response(response=400, description="Invalid request"),
     *     @OA\Response(response=500, description="Internal server error")
     * )
    */

     public function discard_sale($id)
     {
         try {
             $sale = $this->saleService->changeStatus($id, SalesType::DISCARD->name);
             $sale = $this->saleService->getSalebyId($id);
             foreach ($sale->property as $property) {
               $propertydata =  $this->propertiesService->changeStatus($property->id, PropertyStatus::AVAILABLE->value); // Array access
               $this->systemLogService->logActivity('propiedad','Propiedad Habilitada', SeveritySystemLog::info->name);
            }
             $this->bitacoraService->logActivity(ActivityTypes::SALE_UPDATED, $sale->opportunity->customer, ['sales' => $sale]);
             $this->systemLogService->logActivity('venta','Venta descartada', SeveritySystemLog::info->name, $sale);
             return ApiResponse::success(SuccessMessages::UPDATE_SUCCESS, $sale, [], 200);
         } catch (\Exception $e) {

            $this->systemLogService->logActivity('venta','Cambio de estado de venta fallida' , SeveritySystemLog::error->name);
             return ApiResponse::error($e->getMessage(), $e, [], 500);
         }
     }

    /**
     * @OA\PATCH(
     *     path="/api/sale/{id}/status/signature",
     *     summary="Change Status signature to Sales",
     *     tags={"Sales"},
     *   @OA\Parameter(
     *         name="id",
     *         in="path",
     *         description="ID of the sale",
     *         required=true,
     *         @OA\Schema(
     *             type="integer",
     *             format="int64"
     *         )
     *     ),
     *     @OA\Response(response=200, description="Successful operation"),
     *     @OA\Response(response=422, description="Unprocessable Entity"),
     *     @OA\Response(response=400, description="Invalid request"),
     *     @OA\Response(response=500, description="Internal server error")
     * )
     */

    public function change_status_confirmation_signature( $id)
    {
        try {
            $sale = $this->saleService->changeConfirmationSignature($id);
            $sale = $this->saleService->getSalebyId($id);
            $this->bitacoraService->logActivity(ActivityTypes::SALE_UPDATED, $sale->opportunity->customer, ['sales' => $sale]);
            $this->systemLogService->logActivity('venta','Confirmacion de firma' , SeveritySystemLog::info->name, $sale);
            return ApiResponse::success(SuccessMessages::UPDATE_SUCCESS, $sale, [], 200);
        } catch (\Exception $e) {
            $this->systemLogService->logActivity('venta','Confirmacion de Venta fallida' , SeveritySystemLog::error->name);
            return ApiResponse::error($e->getMessage(), $e, [], 500);
        }
    }

    public function sale_export()
    {
        try {
            $sales = $this->saleService->getAllSales();
            $this->systemLogService->logActivity('Exportar','Ventas Exportadas', SeveritySystemLog::info->name);
            return Excel::download(new SaleExport($sales), 'Ventas.xlsx');
        } catch (Exception $e) {
            return ApiResponse::error($e->getMessage(), $e, [], $e->getCode());
        }
    }
}
