import { Injectable, NotFoundException } from '@nestjs/common';
import { TenantConnectionService } from '../../database/tenant-connection.service';
import { CollateralHome } from '../../database/tenant/entities/collateral-home.entity';
import { CollateralVehicle } from '../../database/tenant/entities/collateral-vehicle.entity';
import { CollateralAnshiyar } from '../../database/tenant/entities/collateral-anshiyar.entity';
import { CollateralLandOwner } from '../../database/tenant/entities/collateral-land-owner.entity';
import { CollateralSavings } from '../../database/tenant/entities/collateral-savings.entity';
import { CollateralFixedDeposit } from '../../database/tenant/entities/collateral-fixed-deposit.entity';
import { CollateralMicrofinance } from '../../database/tenant/entities/collateral-microfinance.entity';
import { CollateralGeneral } from '../../database/tenant/entities/collateral-general.entity';
import { EntityTarget, ObjectLiteral } from 'typeorm';

type CollateralType = 'home' | 'vehicle' | 'anshiyar' | 'land-owner' | 'savings' | 'fixed-deposit' | 'microfinance' | 'general';

const ENTITY_MAP: Record<CollateralType, EntityTarget<ObjectLiteral>> = {
  home: CollateralHome,
  vehicle: CollateralVehicle,
  anshiyar: CollateralAnshiyar,
  'land-owner': CollateralLandOwner,
  savings: CollateralSavings,
  'fixed-deposit': CollateralFixedDeposit,
  microfinance: CollateralMicrofinance,
  general: CollateralGeneral,
};

@Injectable()
export class CollateralsService {
  constructor(private tenantConn: TenantConnectionService) {}

  private async repo(sub: string, type: CollateralType) {
    const entity = ENTITY_MAP[type];
    if (!entity) throw new NotFoundException(`Unknown collateral type: ${type}`);
    const ds = await this.tenantConn.getTenantDataSource(sub);
    return ds.getRepository(entity);
  }

  async findByApplication(sub: string, type: CollateralType, applicationId: string) {
    const r = await this.repo(sub, type);
    return r.find({ where: { applicationId } as any });
  }

  async findAll(sub: string, type: CollateralType, applicationId?: string) {
    const r = await this.repo(sub, type);
    const where: any = {};
    if (applicationId) where.applicationId = applicationId;
    return r.find({ where, order: { createdAt: 'ASC' } as any });
  }

  async findOne(sub: string, type: CollateralType, id: string) {
    const r = await this.repo(sub, type);
    const item = await r.findOne({ where: { id } as any });
    if (!item) throw new NotFoundException(`Collateral ${id} not found`);
    return item;
  }

  async create(sub: string, type: CollateralType, dto: any, userId?: string) {
    const r = await this.repo(sub, type);
    const item = r.create({ ...dto, createdBy: userId, updatedBy: userId });
    return r.save(item);
  }

  async update(sub: string, type: CollateralType, id: string, dto: any, userId?: string) {
    await this.findOne(sub, type, id);
    const r = await this.repo(sub, type);
    await r.update(id, { ...dto, updatedBy: userId });
    return this.findOne(sub, type, id);
  }

  async remove(sub: string, type: CollateralType, id: string) {
    const r = await this.repo(sub, type);
    await this.findOne(sub, type, id);
    await r.softDelete(id).catch(() => r.delete(id));
    return { id };
  }

  async bulkUpsert(sub: string, type: CollateralType, applicationId: string, items: any[], userId?: string) {
    const r = await this.repo(sub, type);
    const existing = await r.find({ where: { applicationId } as any });
    const existingIds = new Set(existing.map((e: any) => e.id));
    const incomingIds = new Set(items.filter(i => i.id).map(i => i.id));
    const toDelete = [...existingIds].filter(id => !incomingIds.has(id));
    if (toDelete.length) await r.softDelete(toDelete).catch(() => r.delete(toDelete));
    const saved = [];
    for (const item of items) {
      if (item.id && existingIds.has(item.id)) {
        await r.update(item.id, { ...item, applicationId, updatedBy: userId });
        saved.push(await r.findOne({ where: { id: item.id } as any }));
      } else {
        const created = r.create({ ...item, applicationId, createdBy: userId, updatedBy: userId });
        saved.push(await r.save(created));
      }
    }
    return saved;
  }
}
