import {
  Injectable,
  NotFoundException,
  BadRequestException,
  InternalServerErrorException,
} from '@nestjs/common';
import { ModelsService } from 'src/models/models.service';
import * as Handlebars from 'handlebars';
import {
  CreateEmailTemplateDto,
  TestEmailDto,
  UpdateEmailTemplateDto,
} from './dto/emailtemplate.dto';
import { CommonService } from 'src/common/common.service';
import { MailService, EmailOptions } from 'src/common/services/mail.service';
import * as fs from 'fs';
import * as path from 'path';

@Injectable()
export class EmailTemplateService {
  constructor(
    private readonly models: ModelsService,
    private readonly commonService: CommonService,
    private readonly mailService: MailService,
  ) { }

  // ---------------- CREATE EMAIL TEMPLATE ----------------
  async create(dto: CreateEmailTemplateDto) {
    try {
      if (!dto?.name || !dto?.en?.subject || !dto?.en?.body) {
        throw new BadRequestException(
          'Name, english subject and body are required',
        );
      }

      const existingTemplate = await this.models.EmailTemplateModel.findOne({
        name: dto.name,
      });

      if (existingTemplate) {
        throw new BadRequestException(
          'Email template with this name already exists',
        );
      }

      return await this.models.EmailTemplateModel.create(dto);
    } catch (error) {
      throw error instanceof BadRequestException
        ? error
        : new InternalServerErrorException('Failed to create email template');
    }
  }

  // ---------------- GET ALL EMAIL TEMPLATES ----------------
  async findAll(page = 1, limit = 10) {
    try {
      page = Number(page) || 1;
      limit = Number(limit) || 10;
      const skip = (page - 1) * limit;

      const [data, count] = await Promise.all([
        this.models.EmailTemplateModel.find({})
          .sort({ _id: -1 })
          .skip(skip)
          .limit(limit)
          .lean(),
        this.models.EmailTemplateModel.countDocuments(),
      ]);

      return this.commonService.paginatedResponse(
        'Email templates retrieved successfully',
        data,
        count,
        page,
        limit
      );
    } catch (error) {
      console.error('findAll email templates error:', error);
      throw new InternalServerErrorException(
        'Failed to fetch email templates',
      );
    }
  }


  // ---------------- GET SINGLE EMAIL TEMPLATE ----------------
  async findOne(name: string) {
    try {
      if (!name) {
        throw new BadRequestException('Template name is required');
      }

      const template = await this.models.EmailTemplateModel.findOne({
        name,
      }).lean();

      if (!template) {
        throw new NotFoundException('Email template not found');
      }

      return this.commonService.successResponse(
        'Email template retrieved successfully',
        template
      );
    } catch (error) {
      throw error;
    }
  }

  // ---------------- UPDATE EMAIL TEMPLATE ----------------
  async update(name: string, dto: UpdateEmailTemplateDto) {
    try {
      if (!name) {
        throw new BadRequestException('Template name is required');
      }

      const updated = await this.models.EmailTemplateModel.findOneAndUpdate(
        { name },
        { $set: dto },
        { new: true },
      );

      if (!updated) {
        throw new NotFoundException('Email template not found');
      }

      return this.commonService.successResponse(
        'Email template updated successfully',
        updated
      );
    } catch (error) {
      throw error;
    }
  }

  // ---------------- SEND TEST EMAIL ----------------
  async testEmail(dto: TestEmailDto, req: any) {
    try {
      const { name } = dto;

      const to = 'pal511105@gmail.com';
      const customer_name = 'John Doe';
      const admin_message = 'This is a test email';

      if (!name) {
        throw new BadRequestException('Template name is required');
      }

      const { data: template } = await this.findOne(name);

      const language = this.commonService.getUserLanguage(req);
      const content = template?.[language] || template?.en || {};

      if (!content?.body) {
        throw new BadRequestException(`Email template body is empty for language: ${language}`);
      }

      let compiledHtml: string;

      try {
        const compiledTemplate = Handlebars.compile(content.body);
        compiledHtml = compiledTemplate({
          customer_name,
          admin_message,
        });
      } catch (err) {
        throw new BadRequestException('Error compiling email template');
      }

      const subject = content.subject;

      const emailOptions: EmailOptions = {
        to: to,
        subject: subject,
        html: compiledHtml
      };

      const result = await this.mailService.sendEmail(emailOptions);

      if (!result.success) {
        throw new InternalServerErrorException(`Failed to send test email: ${result.error}`);
      }

      return { message: 'Test email sent successfully' };
    } catch (error) {
      console.error('Test email error:', error);
      throw error;
    }
  }




  // async manualSyncEmailTemplates() {
  //   try {
  //     const filePath = path.join(
  //       process.cwd(),
  //       'readycab-EmailTemplate.json',
  //     );

  //     //  Read JSON file
  //     let jsonTemplates: any[] = [];
  //     if (fs.existsSync(filePath)) {
  //       const fileData = fs.readFileSync(filePath, 'utf8');
  //       try {
  //         jsonTemplates = JSON.parse(fileData);
  //       } catch (parseError) {
  //         console.error('Error parsing JSON templates:', parseError);
  //         jsonTemplates = [];
  //       }
  //     }

  //     //  Get DB templates
  //     const dbTemplates = await this.db.EmailTemplateModel.find({}).lean();

  //     const dbMap = new Map(dbTemplates.map((t: any) => [t.name, t]));
  //     const jsonMap = new Map(jsonTemplates.map((t: any) => [t.name, t]));

  //     let addedToDb = 0;
  //     let addedToJson = 0;

  //     //  JSON → Db
  //     for (const template of jsonTemplates) {
  //       if (!dbMap.has(template.name)) {
  //         await this.db.EmailTemplateModel.create(template);
  //         addedToDb++;
  //       }
  //     }

  //     // DB → JSON
  //     for (const template of dbTemplates) {
  //       if (!jsonMap.has(template.name)) {
  //         jsonTemplates.push(template);
  //         addedToJson++;
  //       }
  //     }

  //     // Write back updated JSON
  //     fs.writeFileSync(filePath, JSON.stringify(jsonTemplates, null, 2));

  //     return {
  //       message: 'Seeding sync completed',
  //       addedToDb,
  //       addedToJson,
  //     };
  //   } catch (error) {
  //     console.error('Manual seeding email templates error:', error);
  //     throw error;
  //   }
  // }

  // Optimized
  async manualSyncEmailTemplates() {
    try {
      const filePath = path.join(process.cwd(), 'email-templates.json');

      // Read JSON
      let jsonTemplates: any[] = [];

      if (fs.existsSync(filePath)) {
        const fileData = await fs.promises.readFile(filePath, 'utf8');
        jsonTemplates = JSON.parse(fileData || '[]');
      }

      // Get DB
      const dbTemplates = await this.models.EmailTemplateModel.find({}).lean();

      const dbMap = new Map(dbTemplates.map(t => [t.name, t]));
      const jsonMap = new Map(jsonTemplates.map(t => [t.name, t]));

      const toInsertInDb: any[] = [];
      const toAddInJson: any[] = [];

      // JSON → DB
      for (const template of jsonTemplates) {
        if (!dbMap.has(template.name)) {
          toInsertInDb.push(template);
        }
      }

      // DB → JSON
      for (const template of dbTemplates) {
        if (!jsonMap.has(template.name)) {
          // const { _id, __v, createdAt, updatedAt, ...clean } = template;
          const { _id, __v, createdAt, updatedAt, ...clean } = template as any;
          toAddInJson.push(clean);
        }
      }

      if (toInsertInDb.length) {
        await this.models.EmailTemplateModel.insertMany(toInsertInDb);
      }

      if (toAddInJson.length) {
        jsonTemplates.push(...toAddInJson);
        await fs.promises.writeFile(
          filePath,
          JSON.stringify(jsonTemplates, null, 2),
        );
      }

      return {
        message: 'Seeding sync completed',
        addedToDb: toInsertInDb.length,
        addedToJson: toAddInJson.length,
      };
    } catch (error) {
      console.error('Manual seeding email templates error:', error);
      throw error;
    }
  }


}
