import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource } from 'typeorm';
import { TempFranchise } from './entities/temp_franchise.entity';
import { FranchiseHistory } from '../franchise_history/entities/franchise_history.entity';
import { UserEntity } from '../user/entities/user.entity';
import { Franchises } from '../franchises/entities/franchises.entity';

@Injectable()
export class TempFranchiseService {
  constructor(
    @InjectRepository(TempFranchise)
    private tempFranchiseRepository: Repository<TempFranchise>,
    @InjectRepository(FranchiseHistory)
    private franchiseHistoryRepository: Repository<FranchiseHistory>,
    @InjectRepository(UserEntity)
    private usersRepository: Repository<UserEntity>,
    @InjectRepository(Franchises)
    private franchisesRepository: Repository<Franchises>,
    private dataSource: DataSource,
  ) {}

  async submitApplication(applicationData: any) {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // Add status field to application data
      const applicationWithStatus = {
        ...applicationData,
        status: 'applied',
      };

      // Insert into temp_franchise
      const tempFranchise = await queryRunner.manager.save(
        TempFranchise,
        applicationWithStatus,
      );

      // Log in franchise_history
      await queryRunner.manager.save(FranchiseHistory, {
        tempFranchiseId: tempFranchise.id,
        action: 'applied',
      });

      await queryRunner.commitTransaction();
      return tempFranchise;
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }

  async getApplications(status?: string, page: number = 1, limit: number = 10) {
    const query = this.tempFranchiseRepository
      .createQueryBuilder('tf')
      .orderBy('tf.created_at', 'DESC');

    if (status) {
      query.where('tf.status = :status', { status });
    }

    // Get total count for pagination
    const total = await query.getCount();

    // Apply pagination
    const offset = (page - 1) * limit;
    query.skip(offset).take(limit);

    const applications = await query.getMany();

    return {
      applications,
      total,
      totalPages: Math.ceil(total / limit),
    };
  }

  async getApplicationById(id: number) {
    return await this.tempFranchiseRepository.findOne({ where: { id } });
  }

  async approveApplication(
    tempFranchiseId: number,
    adminId: number,
    remarks?: string,
  ) {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // Get the temp franchise application
      const tempFranchise = await queryRunner.manager.findOne(TempFranchise, {
        where: { id: tempFranchiseId },
      });

      if (!tempFranchise) {
        throw new Error('Application not found');
      }

      if (tempFranchise.status !== 'applied') {
        throw new Error('Application has already been processed');
      }

      // Check if user already exists by email
      let user = await queryRunner.manager.findOne(UserEntity, {
        where: { email: tempFranchise.email },
      });

      if (!user) {
        // Create new user with OTP authentication (no password needed)
        const username = `franchise_${tempFranchise.phone}_${Date.now()}`;
        user = await queryRunner.manager.save(UserEntity, {
          username: username,
          email: tempFranchise.email,
          phone: tempFranchise.phone,
          password: null, // No password - uses OTP login
          role: 'franchise',
          fullName: tempFranchise.full_name,
          status: 'active',
          authMethod: 'otp',
          phoneVerified: true, // Admin approved, so phone is verified
        });
      }

      // Create franchise
      const franchise = await queryRunner.manager.save(Franchises, {
        userId: user.id,
        franchiseName: tempFranchise.company_name || 'Franchise',
        companyName: tempFranchise.company_name,
        email: tempFranchise.email,
        contactNo: tempFranchise.phone,
        address: tempFranchise.address,
        countryId: tempFranchise.country_id,
        stateId: tempFranchise.state_id,
        cityId: tempFranchise.city_id,
        postal_code: tempFranchise.postal_code,
        gstNo: tempFranchise.gst_number,
        serviceArea: JSON.stringify(tempFranchise.preferred_location),
        status: 'active',
      });

      // Update temp_franchise status
      await queryRunner.manager.update(TempFranchise, tempFranchiseId, {
        status: 'approved',
      });

      // Log in franchise_history
      await queryRunner.manager.save(FranchiseHistory, {
        franchiseId: franchise.id,
        tempFranchiseId: tempFranchiseId,
        action: 'approved',
        performedBy: adminId,
        remarks: remarks || 'Approved by admin',
      });

      await queryRunner.commitTransaction();
      return { franchise, user };
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }

  async rejectApplication(
    tempFranchiseId: number,
    adminId: number,
    remarks?: string,
  ) {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // Get the temp franchise application
      const tempFranchise = await queryRunner.manager.findOne(TempFranchise, {
        where: { id: tempFranchiseId },
      });

      if (!tempFranchise) {
        throw new Error('Application not found');
      }

      if (tempFranchise.status !== 'applied') {
        throw new Error('Application has already been processed');
      }

      // Update temp_franchise status
      await queryRunner.manager.update(TempFranchise, tempFranchiseId, {
        status: 'rejected',
      });

      // Log in franchise_history
      await queryRunner.manager.save(FranchiseHistory, {
        tempFranchiseId: tempFranchiseId,
        action: 'rejected',
        performedBy: adminId,
        remarks: remarks || 'Rejected by admin',
      });

      await queryRunner.commitTransaction();
      return { message: 'Application rejected successfully' };
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }
}
