import fs from 'fs';
import path from 'path';
import { parse } from 'csv-parse';
import { Types } from 'mongoose';

import { Fast2sms } from '@/modules/communication/fast2sms/fast2sms.model';
import { Company } from '@/modules/company/company.model';
import { TriggerPoint } from '@/shared/constants/enum.constant';

const CSV_PATH = path.resolve(
  './src/shared/seeder/fast2sms/all_approved_template.csv',
);

export const storeFast2smsTemplates = async (companyId: Types.ObjectId) =>
  new Promise<{
    total: number;
    processed: number;
    upserted: number;
    modified: number;
    skipped: number;
  }>((resolve, reject) => {
    if (!fs.existsSync(CSV_PATH))
      reject(new Error(`CSV not found at ${CSV_PATH}`));

    const docs: Array<{
      companyId: Types.ObjectId;
      templateId: string;
      variableCount?: string;
      message: string;
      isDefault: boolean;
    }> = [];

    let total = 0;
    let skipped = 0;
    let latestSenderId: string | null = null;

    const stream = fs.createReadStream(CSV_PATH);
    const parser = parse({ columns: true, trim: true });

    stream.on('error', reject);
    parser.on('error', reject);

    parser.on('data', (row: Record<string, unknown>) => {
      total++;

      const templateId = (row['message'] ?? '').toString().trim();
      const message = (row['approved_message'] ?? '').toString().trim();
      const variableCount = (row['variable_count'] ?? '').toString().trim();
      const senderId = (row['sender_id'] ?? '').toString().trim();

      if (senderId) latestSenderId = senderId;

      if (!templateId || !message) {
        skipped++;
        return;
      }

      docs.push({
        companyId,
        templateId,
        variableCount,
        message,
        isDefault: true,
      });
    });

    parser.on('end', async () => {
      try {
        if (latestSenderId)
          await Company.updateOne(
            { _id: companyId },
            { $set: { 'fast2sms.senderId': latestSenderId } },
          );

        if (!docs.length)
          return resolve({
            total,
            processed: 0,
            upserted: 0,
            modified: 0,
            skipped,
          });

        // Upsert by (companyId + templateId)
        const ops = docs.map((d) => ({
          updateOne: {
            filter: { companyId: d.companyId, templateId: d.templateId },
            update: {
              $set: {
                message: d.message,
                variableCount: d.variableCount,
                isDefault: d.isDefault,
                updatedAt: new Date(),
                ...(d.message.includes('OTP')
                  ? { triggerPoint: TriggerPoint.OnLoginMobileApp }
                  : {}),
              },
              $setOnInsert: {
                companyId: d.companyId,
                templateId: d.templateId,
                createdAt: new Date(),
              },
            },
            upsert: true,
          },
        }));

        const res = await Fast2sms.bulkWrite(ops, { ordered: false });

        const upserted =
          res.upsertedCount ??
          (res.upsertedIds ? Object.keys(res.upsertedIds).length : 0);

        const modified = res.modifiedCount ?? 0;

        resolve({
          total,
          processed: docs.length,
          upserted,
          modified,
          skipped,
        });
      } catch (err) {
        reject(err);
      }
    });

    stream.pipe(parser);
  });
