import { Controller, Get, Post, Body, Param, UseGuards, Res, Req, HttpException, Query, Put, Patch, Delete } from '@nestjs/common';
import { SaveCardDto } from './dto/save-card.dto';
import { ApiBearerAuth, ApiBody, ApiTags } from '@nestjs/swagger';
import { AdminGuard } from '../auth/guards/admin.guard';
import { response } from 'express';
import { responseMessages } from 'src/messages/response-messages';
import { toJsonResponse } from 'src/common/response';
import { PaymentService } from './payment.service';
import { BrandGuard } from '../auth/guards/brand.guard';
import { SubscriptionDto } from './dto/subscription.dto';
import { DeleteCardDto } from './dto/card-delete.dto';
import { SubscriptionCancelDto } from './dto/subscription-cancel.dto';
import { SubscriptionPaymentExportDto } from './dto/subscription-export-payment.dto';
import { AdminBrandGuard } from '../auth/guards/admin-brand.guard';
import { QueryCommonGuard } from '../auth/guards/common-query.guard';
import { ReactiveSubscription } from './dto/reactive-subscription';
import { SubscriptionLinkDto } from './dto/subscription-link.dto';
import { SubscriptionHistoryInvoiceDto } from './dto/subscription-history-invoice.dto';

@ApiTags('payment')
@Controller('payment')
export class PaymentController {
    constructor(private readonly paymentService: PaymentService) { }

    /**
     * Create a new payment plan.
     * 
     * @param saveCard - The card details for the plan creation.
     * @param req - The incoming request object, containing the authenticated user.
     * @param response - The response object for sending HTTP responses.
     * 
     * @returns A promise that resolves to a 201 status code upon successful creation.
     * 
     * @throws Returns an error response with the appropriate status and message if an exception occurs.
     */
    @ApiBearerAuth('access-token')
    @ApiBody({ type: SaveCardDto })
    @UseGuards(BrandGuard)
    @Post('save-card')
    async saveCard(@Body() saveCard: SaveCardDto, @Req() req, @Res() response) {
        try {
            await this.paymentService.saveCard(saveCard, req.user);
            return response.status(201).json();
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(BrandGuard)
    @Get('cards')
    async getCard(@Req() req, @Res() response) {
        try {
            const data = await this.paymentService.getCard(req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @ApiBody({ type: SubscriptionDto })
    @UseGuards(AdminBrandGuard)
    @Post('subscription')
    async subscription(@Body() body: SubscriptionDto, @Req() req, @Res() response) {
        try {
            const data = await this.paymentService.subscription(body, req.user);
            return response.status(201).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(BrandGuard)
    @Get('subscription')
    async subscriptionList(@Req() req, @Res() response) {
        try {
            const data = await this.paymentService.subscriptionList(req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(AdminBrandGuard)
    @Get('subscription-history')
    async subscriptionHistory(@Query() queryParam: any, @Req() req, @Res() response) {
        try {
            const data = await this.paymentService.subscriptionHistory(queryParam, req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @UseGuards(QueryCommonGuard)
    @ApiBearerAuth('access-token')
    @Get('subscription-history/export')
    async subscriptionHistoryExport(@Query() queryParam: SubscriptionPaymentExportDto, @Req() req, @Res() response) {
        try {
            const data = await this.paymentService.subscriptionHistoryExport(queryParam, response);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @ApiBody({ type: SubscriptionCancelDto })
    @UseGuards(BrandGuard)
    @Patch('subscription/cancel/:subscription_id')
    async subscriptionCancel(@Param() param: SubscriptionCancelDto, @Req() req, @Res() response) {
        try {
            await this.paymentService.subscriptionCancel(param, req.user);
            return response.status(201).json();
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @ApiBody({ type: SubscriptionCancelDto })
    @UseGuards(BrandGuard)
    @Patch('schedule/cancel/:subscription_id')
    async subscriptionCancelSchedule(@Param() param: SubscriptionCancelDto, @Req() req, @Res() response) {
        try {
            await this.paymentService.subscriptionCancelSchedule(param, req.user);
            return response.status(201).json();
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @ApiBody({ type: DeleteCardDto })
    @UseGuards(BrandGuard)
    @Delete('card/:card_id')
    async deleteCard(@Param() param: DeleteCardDto, @Req() req, @Res() response) {
        try {
            await this.paymentService.deleteCard(param, req.user);
            return response.status(201).json();
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }


    @ApiBearerAuth('access-token')
    @UseGuards(AdminBrandGuard)
    @Get("brand/permissions")
    async userPermission(@Req() req, @Res() response) {
        try {
            const data = await this.paymentService.getUserPermissions(req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(AdminBrandGuard)
    @Get("client/secret")
    async clientSecret(@Req() req, @Res() response) {
        try {
            const data = await this.paymentService.clientSecret(req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(BrandGuard)
    @Get('activated/subscription')
    async activatedSubscription(@Req() req, @Res() response) {
        try {
            const data = await this.paymentService.activatedSubscription(req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(BrandGuard)
    @Get('billing-portal')
    async billingPortal(@Req() req, @Res() response) {
        try {
            const data = await this.paymentService.billingPortal(req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(AdminBrandGuard)
    @Get('subscription-history/:subscription_history_id/invoice')
    async getInvoiceLink(@Param() param: SubscriptionHistoryInvoiceDto, @Req() req, @Res() response) {
        try {
            const data = await this.paymentService.getInvoiceLink(param, req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth('access-token')
    @UseGuards(AdminBrandGuard)
    @Post('subscription/link')
    async subscriptionLink(@Body() body: SubscriptionLinkDto, @Req() req, @Res() response) {
        try {
            const data = await this.paymentService.subscriptionLink(body, req.user);
            return response.status(200).json(data);
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message));
        }
    }

    @ApiBearerAuth("access-token")
    @UseGuards(BrandGuard)
    @Patch("re-activate/subscription/:subscription_id")
    async reactivateSubscription(@Param() param: ReactiveSubscription, @Req() req, @Res() response: any) {
        try {
            const data = await this.paymentService.reactivateSubscription(param, req.user)
            response.status(201).json(data)
        } catch (error) {
            console.log(error)
            response.status(error.status).json(toJsonResponse(error.status, error.message))
        }
    }
}
