/* eslint-disable */
// @ts-ignore
declare module '@paypal/checkout-server-sdk';

import { HttpStatus, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { checkoutNodeJssdk } from '@paypal/checkout-server-sdk';
import axios from 'axios';
import { Result, Ok, Err } from 'oxide.ts';
import { Exception } from 'src/utils/exception';

@Injectable()
export class PayPalWrapper {
    private client: checkoutNodeJssdk.core.PayPalHttpClient;
    private clientId: string;
    private clientSecret: string;

    constructor(private configService: ConfigService) {
        if (!process.env.PAYPAL_CLIENT_ID)
            throw new Exception(HttpStatus.INTERNAL_SERVER_ERROR, ["Can't find PAYPAL_CLIENT_ID env"]);
        if (!process.env.PAYPAL_CLIENT_SECRET)
            throw new Exception(HttpStatus.INTERNAL_SERVER_ERROR, ["Can't find PAYPAL_CLIENT_SECRET env"]);

        this.clientId = process.env.PAYPAL_CLIENT_ID;
        this.clientSecret = process.env.PAYPAL_CLIENT_SECRET;

        const environment = new checkoutNodeJssdk.core.SandboxEnvironment(
            this.clientId,
            this.clientSecret
        );
        this.client = new checkoutNodeJssdk.core.PayPalHttpClient(environment);
    }

    async createOrder(amount: string, currency: string): Promise<Result<string, Exception>> {
        try {
            const request = new checkoutNodeJssdk.orders.OrdersCreateRequest();
            request.requestBody({
                intent: 'CAPTURE',
                purchase_units: [{
                    amount: {
                        currency_code: currency,
                        value: amount
                    }
                }]
            });

            const response = await this.client.execute(request);
            return Ok(response.result.id);
        } catch (error) {
            return Err(new Exception(500, ['Failed to create PayPal order: ' + (error as string)]));
        }
    }

    // Create a product/item in PayPal Catalog
    async createProduct(data: { name: string; description?: string }): Promise<Result<string, Exception>> {
        try {
            const accessToken = await this.getAccessToken();
            const response = await axios.post(
                'https://api-m.sandbox.paypal.com/v1/catalogs/products',
                {
                    name: data.name,
                    description: data.description,
                    type: 'SERVICE',
                    category: 'SOFTWARE',
                },
                {
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${accessToken}`,
                    },
                }
            );
            return Ok(response.data.id);
        } catch (error: any) {
            const msg = error.response?.data || error.message || String(error);
            return Err(new Exception(500, ['Failed to create PayPal product: ' + JSON.stringify(msg)]));
        }
    }

    // Update a product/item in PayPal Catalog
    async updateProduct(productId: string, data: { name?: string; description?: string }): Promise<Result<void, Exception>> {
        try {
            const accessToken = await this.getAccessToken();
            const patchData = [];
            if (data.name) patchData.push({ op: 'replace', path: '/name', value: data.name });
            if (data.description) patchData.push({ op: 'replace', path: '/description', value: data.description });
            if (patchData.length === 0) return Ok(void 0);

            await axios.patch(
                `https://api-m.sandbox.paypal.com/v1/catalogs/products/${productId}`,
                patchData,
                {
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${accessToken}`,
                    },
                }
            );
            return Ok(void 0);
        } catch (error: any) {
            const msg = error.response?.data || error.message || String(error);
            return Err(new Exception(500, ['Failed to update PayPal product: ' + JSON.stringify(msg)]));
        }
    }

    // Get OAuth2 access token for PayPal REST API
    private async getAccessToken(): Promise<string> {
        const basic = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64');
        const response = await axios.post(
            'https://api-m.sandbox.paypal.com/v1/oauth2/token',
            'grant_type=client_credentials',
            {
                headers: {
                    'Authorization': `Basic ${basic}`,
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
            }
        );
        return response.data.access_token;
    }

    async captureOrder(orderId: string): Promise<Result<any, Exception>> {
        try {
            const request = new checkoutNodeJssdk.orders.OrdersCaptureRequest(orderId);
            const response = await this.client.execute(request);
            return Ok(response.result);
        } catch (error) {
            return Err(new Exception(500, ['Failed to capture PayPal order: ' + (error as string)]));
        }
    }
}
mport { checkoutNodeJssdk } from '@paypal/checkout-server-sdk'; doesnt work