const db = require('../../database/database');
const { logger } = require('../../middleware/logger');
const { normalizeLanguageCode } = require('../../utils/languageUtils');

const ALLOWED_USER_TYPES = new Set(['personal', 'company', 'both']);
const ALLOWED_CONTRACT_TYPES = new Set(['contract', 'gdpr', 'abo']);
const ALLOWED_INVOICE_TAX_MODES = new Set(['standard', 'reverse_charge', 'both']);

function normalizeTemplateUserType(value) {
  return ALLOWED_USER_TYPES.has(value) ? value : 'both';
}

function normalizeContractType(value) {
  return (value === undefined || value === null) ? value : String(value).trim().toLowerCase();
}

function normalizeInvoiceTaxMode(value) {
  if (value === undefined || value === null || String(value).trim() === '') return 'both';
  const normalized = String(value).trim().toLowerCase();
  return ALLOWED_INVOICE_TAX_MODES.has(normalized) ? normalized : 'both';
}

class DocumentTemplateRepository {
  async create(data, conn) {
    logger.info('DocumentTemplateRepository.create:start', { name: data.name, type: data.type });
    // ADDED: validate required fields + normalize optional fields
    const required = ['name', 'type', 'storageKey', 'lang'];
    for (const k of required) {
      const v = data[k];
      if (v === undefined || v === null || String(v).trim() === '') {
        const err = new Error(`Invalid document template: missing field "${k}"`);
        err.code = 'INVALID_TEMPLATE_DATA';
        logger.error('DocumentTemplateRepository.create:invalid', { field: k });
        throw err;
      }
    }
    const name = String(data.name);
    const type = String(data.type);
    const storageKey = String(data.storageKey);
    const description = data.description === undefined ? null : data.description; // avoid undefined bind
    const lang = String(data.lang);
    const user_type = normalizeTemplateUserType(data.user_type || data.userType);
    const contract_type = type === 'contract'
      ? (ALLOWED_CONTRACT_TYPES.has(normalizeContractType(data.contract_type || data.contractType)) ? normalizeContractType(data.contract_type || data.contractType) : null)
      : null;
    const finalContractType = type === 'contract' ? (contract_type || 'contract') : null;
    const tax_mode = type === 'invoice'
      ? normalizeInvoiceTaxMode(data.tax_mode || data.taxMode)
      : null;

    const version = Number.isFinite(Number(data.version)) ? Math.max(1, Number(data.version)) : 1;
    const state = (data.state === 'active' || data.state === 'inactive') ? data.state : 'inactive';

    const query = `
      INSERT INTO document_templates (name, type, contract_type, storageKey, description, lang, user_type, tax_mode, version, state, createdAt, updatedAt)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
    `;
    try {
      if (conn) {
        const [res] = await conn.execute(query, [name, type, finalContractType, storageKey, description, lang, user_type, tax_mode, version, state]);
        const insertId = res && (res.insertId || res[0]?.insertId);
        logger.info('DocumentTemplateRepository.create:success', { id: insertId || res.insertId });
        return { id: insertId || res.insertId, name, type, contract_type: finalContractType, storageKey, description, lang, user_type, tax_mode, version, state };
      }
      const result = await db.execute(query, [name, type, finalContractType, storageKey, description, lang, user_type, tax_mode, version, state]);
      const insertId = result && result.insertId ? result.insertId : (Array.isArray(result) && result[0] && result[0].insertId ? result[0].insertId : undefined);
      logger.info('DocumentTemplateRepository.create:success', { id: insertId });
      return { id: insertId, name, type, contract_type: finalContractType, storageKey, description, lang, user_type, tax_mode, version, state };
    } catch (error) {
      logger.error('DocumentTemplateRepository.create:error', { error: error.message });
      throw error;
    }
  }

  async findAll(conn) {
    logger.info('DocumentTemplateRepository.findAll:start');
    const query = `SELECT * FROM document_templates ORDER BY createdAt DESC`;
    try {
      if (conn) {
        const [rows] = await conn.execute(query);
        logger.info('DocumentTemplateRepository.findAll:success');
        return rows;
      }
      const result = await db.execute(query);
      // db.execute may return rows directly or [rows, fields]
      if (Array.isArray(result) && Array.isArray(result[0])) return result[0];
      logger.info('DocumentTemplateRepository.findAll:success');
      return result;
    } catch (error) {
      logger.error('DocumentTemplateRepository.findAll:error', { error: error.message });
      throw error;
    }
  }

  async findById(id, conn) {
    logger.info('DocumentTemplateRepository.findById:start', { id });
    const query = `SELECT * FROM document_templates WHERE id = ? LIMIT 1`;
    try {
      if (conn) {
        const [rows] = await conn.execute(query, [id]);
        logger.info('DocumentTemplateRepository.findById:success', { id });
        return (rows && rows[0]) ? rows[0] : null;
      }
      const result = await db.execute(query, [id]);
      if (Array.isArray(result) && Array.isArray(result[0])) {
        return result[0][0] || null;
      }
      logger.info('DocumentTemplateRepository.findById:success', { id });
      return (result && result[0]) ? result[0] : null;
    } catch (error) {
      logger.error('DocumentTemplateRepository.findById:error', { id, error: error.message });
      throw error;
    }
  }

  async update(id, data, conn) {
    logger.info('DocumentTemplateRepository.update:start', { id, data });
    // data: { name, type, storageKey, description, lang, version }
    const fields = [];
    const values = [];
    for (const key of ['name', 'type', 'contract_type', 'storageKey', 'description', 'lang', 'version', 'user_type', 'tax_mode']) {
      if (data[key] !== undefined) {
        fields.push(`${key} = ?`);
        values.push(data[key]);
      }
    }
    // Support camelCase input
    if (data.userType !== undefined && data.user_type === undefined) {
      fields.push(`user_type = ?`);
      values.push(data.userType);
    }
    if (data.taxMode !== undefined && data.tax_mode === undefined) {
      fields.push(`tax_mode = ?`);
      values.push(data.taxMode);
    }
    // Do not update state here
    if (!fields.length) return false;
    const query = `
      UPDATE document_templates SET ${fields.join(', ')}, updatedAt = NOW()
      WHERE id = ?
    `;
    values.push(id);
    try {
      if (conn) await conn.execute(query, values);
      else await db.execute(query, values);
      logger.info('DocumentTemplateRepository.update:success', { id });
      return true;
    } catch (error) {
      logger.error('DocumentTemplateRepository.update:error', { id, error: error.message });
      throw error;
    }
  }

  async updateState(id, state, conn) {
    logger.info('DocumentTemplateRepository.updateState:start', { id, state });
    const query = `
      UPDATE document_templates SET state = ?, updatedAt = NOW()
      WHERE id = ?
    `;
    try {
      if (conn) await conn.execute(query, [state, id]);
      else await db.execute(query, [state, id]);
      logger.info('DocumentTemplateRepository.updateState:success', { id, state });
      return true;
    } catch (error) {
      logger.error('DocumentTemplateRepository.updateState:error', { id, error: error.message });
      throw error;
    }
  }

  // Deactivate other active contract templates that would conflict with the one being activated.
  // Conflict dimensions:
  // - same type='contract'
  // - same contract_type ('contract' | 'gdpr')
  // - same lang
  // - overlapping user_type (personal/company/both)
  async deactivateOtherActiveContracts({ excludeId, contract_type, lang, user_type }, conn) {
    logger.info('DocumentTemplateRepository.deactivateOtherActiveContracts:start', { excludeId, contract_type, lang, user_type });
    const normalizedContractType = (contract_type === undefined || contract_type === null) ? '' : String(contract_type).trim().toLowerCase();
    const safeContractType = (normalizedContractType === 'gdpr' || normalizedContractType === 'contract' || normalizedContractType === 'abo')
      ? normalizedContractType
      : 'contract';
    const safeLang = normalizeLanguageCode(lang) || 'en';
    const safeUserType = (user_type === 'personal' || user_type === 'company' || user_type === 'both') ? user_type : 'both';

    // user_type overlap rules
    const overlap = safeUserType === 'both'
      ? ['personal', 'company', 'both']
      : [safeUserType, 'both'];

    const query = `
      UPDATE document_templates
      SET state = 'inactive', updatedAt = NOW()
      WHERE id <> ?
        AND type = 'contract'
        AND (
          contract_type = ?
          OR (contract_type IS NULL AND ? = 'contract')
        )
        AND lang = ?
        AND state = 'active'
        AND (
          user_type IN (${overlap.map(() => '?').join(', ')})
          OR user_type IS NULL
        )
    `;
    const params = [excludeId, safeContractType, safeContractType, safeLang, ...overlap];
    try {
      if (conn) {
        const [res] = await conn.execute(query, params);
        logger.info('DocumentTemplateRepository.deactivateOtherActiveContracts:success', { affected: res?.affectedRows });
        return res?.affectedRows || 0;
      }
      const res = await db.execute(query, params);
      logger.info('DocumentTemplateRepository.deactivateOtherActiveContracts:success', { affected: res?.affectedRows });
      return res?.affectedRows || 0;
    } catch (error) {
      logger.error('DocumentTemplateRepository.deactivateOtherActiveContracts:error', { error: error.message });
      throw error;
    }
  }

  // Deactivate other active invoice templates for the same language and user_type.
  async deactivateOtherActiveInvoices({ excludeId, lang, user_type, tax_mode }, conn) {
    logger.info('DocumentTemplateRepository.deactivateOtherActiveInvoices:start', { excludeId, lang, user_type, tax_mode });
    const safeLang = normalizeLanguageCode(lang) || 'en';
    const safeUserType = normalizeTemplateUserType(user_type);
    const safeTaxMode = normalizeInvoiceTaxMode(tax_mode);

    const query = `
      UPDATE document_templates
      SET state = 'inactive', updatedAt = NOW()
      WHERE id <> ?
        AND type = 'invoice'
        AND lang = ?
        AND COALESCE(user_type, 'both') = ?
        AND COALESCE(tax_mode, 'both') = ?
        AND state = 'active'
    `;
    const params = [excludeId, safeLang, safeUserType, safeTaxMode];
    try {
      if (conn) {
        const [res] = await conn.execute(query, params);
        logger.info('DocumentTemplateRepository.deactivateOtherActiveInvoices:success', { affected: res?.affectedRows });
        return res?.affectedRows || 0;
      }
      const res = await db.execute(query, params);
      logger.info('DocumentTemplateRepository.deactivateOtherActiveInvoices:success', { affected: res?.affectedRows });
      return res?.affectedRows || 0;
    } catch (error) {
      logger.error('DocumentTemplateRepository.deactivateOtherActiveInvoices:error', { error: error.message });
      throw error;
    }
  }

  async delete(id, conn) {
    logger.info('DocumentTemplateRepository.delete:start', { id });
    const query = `DELETE FROM document_templates WHERE id = ?`;
    try {
      if (conn) await conn.execute(query, [id]);
      else await db.execute(query, [id]);
      logger.info('DocumentTemplateRepository.delete:success', { id });
      return true;
    } catch (error) {
      logger.error('DocumentTemplateRepository.delete:error', { id, error: error.message });
      throw error;
    }
  }

  async findActiveByUserType(userType, templateType = null, contractType = null, taxMode = null, conn) {
    logger.info('DocumentTemplateRepository.findActiveByUserType:start', { userType, templateType, contractType, taxMode });
    const safeType = userType === 'both' ? 'both' : (userType === 'personal' || userType === 'company') ? userType : 'personal';
    const normalizedTemplateType = templateType ? String(templateType).trim().toLowerCase() : null;
    let query = safeType === 'both'
      ? `SELECT * FROM document_templates WHERE state = 'active' AND user_type = 'both'`
      : `SELECT * FROM document_templates WHERE state = 'active' AND (user_type = ? OR user_type = 'both')`;
    const params = safeType === 'both' ? [] : [safeType];
    if (normalizedTemplateType) {
      query += ` AND type = ?`;
      params.push(normalizedTemplateType);
    }
    if (contractType && normalizedTemplateType === 'contract') {
      query += ` AND contract_type = ?`;
      params.push(contractType);
    }
    if (normalizedTemplateType === 'invoice' && taxMode) {
      const safeTaxMode = normalizeInvoiceTaxMode(taxMode);
      if (safeTaxMode === 'both') {
        query += ` AND COALESCE(tax_mode, 'both') = 'both'`;
      } else {
        query += ` AND COALESCE(tax_mode, 'both') IN (?, 'both')`;
        params.push(safeTaxMode);
      }
    }
    query += ` ORDER BY createdAt DESC`;
    try {
      if (conn) {
        const [rows] = await conn.execute(query, params);
        logger.info('DocumentTemplateRepository.findActiveByUserType:success', { count: rows.length });
        return rows;
      }
      const result = await db.execute(query, params);
      const rows = Array.isArray(result) && Array.isArray(result[0]) ? result[0] : result;
      logger.info('DocumentTemplateRepository.findActiveByUserType:success', { count: rows.length });
      return rows;
    } catch (error) {
      logger.error('DocumentTemplateRepository.findActiveByUserType:error', { error: error.message });
      throw error;
    }
  }
}

module.exports = new DocumentTemplateRepository();
