import { Injectable } from "@nestjs/common";
import { DataSource, FindOptionsWhere, QueryDeepPartialEntity, QueryRunner, Repository } from "typeorm";
import { PaymentEntity } from "./entities/payment.entity";

@Injectable()
export class PaymentRepository {
    private readonly paymentRepo: Repository<PaymentEntity>;
    constructor(private readonly dataSource: DataSource) {
        this.paymentRepo = this.dataSource.getRepository(PaymentEntity)
    }

    async createTr(qr: QueryRunner, data: Pick<PaymentEntity, "amount" | "method" | "currency" | "type" | "refId" | "merchantOrderId" | "rawInitiation" | "clientAction" | "expiresAt" | "reason">): Promise<PaymentEntity> {
        const payment = qr.manager.create(PaymentEntity, data)
        return qr.manager.save(payment)
    }

    async create(data: Pick<PaymentEntity, "amount" | "method" | "currency" | "type" | "refId" | "merchantOrderId" | "rawInitiation" | "clientAction" | "expiresAt" | "reason">): Promise<PaymentEntity> {
        const payment = this.paymentRepo.create(data)
        return this.paymentRepo.save(payment)
    }



    findOneBy(options: FindOptionsWhere<PaymentEntity> | FindOptionsWhere<PaymentEntity>[]): Promise<PaymentEntity | null> {
        return this.paymentRepo.findOneBy(options);
    }

    update(where: FindOptionsWhere<PaymentEntity>, data: QueryDeepPartialEntity<PaymentEntity>) {
        return this.paymentRepo.update(where, data)
    }

    getActivePaymentByRefIdAndMethod(refId: string, method: PaymentEntity["method"]) {
        return this.paymentRepo
            .createQueryBuilder('payment')
            .where('payment.method = :method', { method })
            .andWhere('payment.refId = :refId', { refId })
            .andWhere('payment.status IN (:...statuses)', {
                statuses: ['action-required'],
            })
            .andWhere('payment.expiresAt > :now', { now: new Date() })
            .getOne();
    }





    getActivePaymentByOrderIdAndMethod(orderId: string, method: PaymentEntity["method"]) {
        return this.paymentRepo
            .createQueryBuilder('payment')
            .where('payment.method = :method', { method })
            .andWhere('payment.merchantOrderId = :orderId', { orderId })
            .andWhere('payment.status IN (:...statuses)', {
                statuses: ['action-required'],
            })
            .andWhere('payment.expiresAt > :now', { now: new Date() })
            .getOne();
    }

    createQueryBuilder(alias: string) {
        return this.paymentRepo.createQueryBuilder(alias);
    }

    async findByCompanyId(companyId: string): Promise<{
        id: string;
        merchantOrderId: string;
        bookingReference: string;
        amount: number;
        currency: string;
        method: string;
        status: string;
        paidAt: Date | null;
        createdAt: Date;
    }[]> {
        const rows: {
            id: string;
            merchant_order_id: string;
            booking_reference: string;
            amount: number;
            currency: string;
            method: string;
            status: string;
            paid_at: Date | null;
            created_at: Date;
        }[] = await this.dataSource.query(
            `SELECT p.id,
                    p.merchant_order_id,
                    b.reference AS booking_reference,
                    p.amount,
                    p.currency,
                    p.method,
                    p.status,
                    p.paid_at,
                    p.created_at
               FROM freight.payments p
               JOIN freight.bookings b ON b.id = p.ref_id
              WHERE b.company_id = $1
                AND p.deleted_at IS NULL
                AND b.deleted_at IS NULL
              ORDER BY p.created_at DESC`,
            [companyId],
        );
        return rows.map((r) => ({
            id: r.id,
            merchantOrderId: r.merchant_order_id,
            bookingReference: r.booking_reference,
            amount: Number(r.amount),
            currency: r.currency,
            method: r.method,
            status: r.status,
            paidAt: r.paid_at,
            createdAt: r.created_at,
        }));
    }

}