import pool from '../config/database';
import logger from '../utils/logger';

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function calculateNextDueDate(intervall: string | null, intervall_tage: number | null): Date | null {
  const now = new Date();
  if (intervall_tage && intervall_tage > 0) {
    now.setDate(now.getDate() + intervall_tage);
    return now;
  }
  switch (intervall) {
    case 'weekly':
      now.setDate(now.getDate() + 7);
      return now;
    case 'monthly':
      now.setMonth(now.getMonth() + 1);
      return now;
    case 'quarterly':
      now.setMonth(now.getMonth() + 3);
      return now;
    case 'halfyearly':
      now.setMonth(now.getMonth() + 6);
      return now;
    case 'yearly':
      now.setFullYear(now.getFullYear() + 1);
      return now;
    default:
      return null;
  }
}

// Subquery fragments for junction table arrays
const JUNCTION_SUBQUERIES = `
  ARRAY(SELECT fahrzeug_typ_id FROM checklist_vorlage_fahrzeug_typen WHERE vorlage_id = v.id) AS fahrzeug_typ_ids,
  ARRAY(SELECT fahrzeug_id::text FROM checklist_vorlage_fahrzeuge WHERE vorlage_id = v.id) AS fahrzeug_ids,
  ARRAY(SELECT ausruestung_typ_id FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = v.id) AS ausruestung_typ_ids,
  ARRAY(SELECT ausruestung_id::text FROM checklist_vorlage_ausruestung WHERE vorlage_id = v.id) AS ausruestung_ids,
  ARRAY(SELECT ft.name FROM checklist_vorlage_fahrzeug_typen cvft JOIN fahrzeug_typen ft ON ft.id = cvft.fahrzeug_typ_id WHERE cvft.vorlage_id = v.id) AS fahrzeug_typ_names,
  ARRAY(SELECT f.bezeichnung FROM checklist_vorlage_fahrzeuge cvf JOIN fahrzeuge f ON f.id = cvf.fahrzeug_id WHERE cvf.vorlage_id = v.id) AS fahrzeug_names,
  ARRAY(SELECT at2.name FROM checklist_vorlage_ausruestung_typen cvat JOIN ausruestung_typen at2 ON at2.id = cvat.ausruestung_typ_id WHERE cvat.vorlage_id = v.id) AS ausruestung_typ_names,
  ARRAY(SELECT a.bezeichnung FROM checklist_vorlage_ausruestung cva JOIN ausruestung a ON a.id = cva.ausruestung_id WHERE cva.vorlage_id = v.id) AS ausruestung_names
`;

// Helper: insert rows into junction tables within a transaction client
async function insertJunctionRows(client: any, vorlageId: number, data: {
  fahrzeug_typ_ids?: number[];
  fahrzeug_ids?: string[];
  ausruestung_typ_ids?: number[];
  ausruestung_ids?: string[];
}) {
  if (data.fahrzeug_typ_ids?.length) {
    for (const id of data.fahrzeug_typ_ids) {
      await client.query(
        `INSERT INTO checklist_vorlage_fahrzeug_typen (vorlage_id, fahrzeug_typ_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
        [vorlageId, id]
      );
    }
  }
  if (data.fahrzeug_ids?.length) {
    for (const id of data.fahrzeug_ids) {
      await client.query(
        `INSERT INTO checklist_vorlage_fahrzeuge (vorlage_id, fahrzeug_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
        [vorlageId, id]
      );
    }
  }
  if (data.ausruestung_typ_ids?.length) {
    for (const id of data.ausruestung_typ_ids) {
      await client.query(
        `INSERT INTO checklist_vorlage_ausruestung_typen (vorlage_id, ausruestung_typ_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
        [vorlageId, id]
      );
    }
  }
  if (data.ausruestung_ids?.length) {
    for (const id of data.ausruestung_ids) {
      await client.query(
        `INSERT INTO checklist_vorlage_ausruestung (vorlage_id, ausruestung_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
        [vorlageId, id]
      );
    }
  }
}

// Helper: delete all junction rows for a vorlage
async function deleteJunctionRows(client: any, vorlageId: number) {
  await client.query(`DELETE FROM checklist_vorlage_fahrzeug_typen WHERE vorlage_id = $1`, [vorlageId]);
  await client.query(`DELETE FROM checklist_vorlage_fahrzeuge WHERE vorlage_id = $1`, [vorlageId]);
  await client.query(`DELETE FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = $1`, [vorlageId]);
  await client.query(`DELETE FROM checklist_vorlage_ausruestung WHERE vorlage_id = $1`, [vorlageId]);
}

// "Global" template condition: no rows in any junction table
const GLOBAL_TEMPLATE_CONDITION = `
  NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeug_typen WHERE vorlage_id = v.id)
  AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeuge WHERE vorlage_id = v.id)
  AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = v.id)
  AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung WHERE vorlage_id = v.id)
`;

// ---------------------------------------------------------------------------
// Vorlagen (Templates)
// ---------------------------------------------------------------------------

async function getVorlagen(filter?: { aktiv?: boolean }) {
  try {
    const conditions: string[] = [];
    const values: any[] = [];
    let idx = 1;

    if (filter?.aktiv !== undefined) {
      conditions.push(`v.aktiv = $${idx}`);
      values.push(filter.aktiv);
      idx++;
    }

    const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
    const result = await pool.query(
      `SELECT v.*,
              ${JUNCTION_SUBQUERIES}
       FROM checklist_vorlagen v
       ${where}
       ORDER BY v.name ASC`,
      values
    );
    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getVorlagen failed', { error });
    throw new Error('Vorlagen konnten nicht geladen werden');
  }
}

async function getVorlageById(id: number) {
  try {
    const vorlageResult = await pool.query(
      `SELECT v.*,
              ${JUNCTION_SUBQUERIES}
       FROM checklist_vorlagen v
       WHERE v.id = $1`,
      [id]
    );
    if (vorlageResult.rows.length === 0) return null;

    const vorlage = vorlageResult.rows[0];
    const itemsResult = await pool.query(
      `SELECT * FROM checklist_vorlage_items WHERE vorlage_id = $1 ORDER BY sort_order ASC, id ASC`,
      [id]
    );
    vorlage.items = itemsResult.rows;
    return vorlage;
  } catch (error) {
    logger.error('ChecklistService.getVorlageById failed', { error, id });
    throw new Error('Vorlage konnte nicht geladen werden');
  }
}

async function createVorlage(data: {
  name: string;
  fahrzeug_typ_ids?: number[];
  fahrzeug_ids?: string[];
  ausruestung_typ_ids?: number[];
  ausruestung_ids?: string[];
  intervall?: string | null;
  intervall_tage?: number | null;
  beschreibung?: string | null;
}) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    const result = await client.query(
      `INSERT INTO checklist_vorlagen (name, intervall, intervall_tage, beschreibung)
       VALUES ($1, $2, $3, $4)
       RETURNING *`,
      [data.name, data.intervall ?? null, data.intervall_tage ?? null, data.beschreibung ?? null]
    );
    const vorlage = result.rows[0];

    await insertJunctionRows(client, vorlage.id, data);

    await client.query('COMMIT');
    return getVorlageById(vorlage.id);
  } catch (error) {
    await client.query('ROLLBACK').catch(() => {});
    logger.error('ChecklistService.createVorlage failed', { error });
    throw new Error('Vorlage konnte nicht erstellt werden');
  } finally {
    client.release();
  }
}

async function updateVorlage(id: number, data: {
  name?: string;
  fahrzeug_typ_ids?: number[];
  fahrzeug_ids?: string[];
  ausruestung_typ_ids?: number[];
  ausruestung_ids?: string[];
  intervall?: string | null;
  intervall_tage?: number | null;
  beschreibung?: string | null;
  aktiv?: boolean;
}) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');

    // Build SET clauses for scalar fields only
    const setClauses: string[] = [];
    const values: any[] = [];
    let idx = 1;

    if (data.name !== undefined) { setClauses.push(`name = $${idx}`); values.push(data.name); idx++; }
    if ('intervall' in data) { setClauses.push(`intervall = $${idx}`); values.push(data.intervall); idx++; }
    if ('intervall_tage' in data) { setClauses.push(`intervall_tage = $${idx}`); values.push(data.intervall_tage); idx++; }
    if ('beschreibung' in data) { setClauses.push(`beschreibung = $${idx}`); values.push(data.beschreibung); idx++; }
    if (data.aktiv !== undefined) { setClauses.push(`aktiv = $${idx}`); values.push(data.aktiv); idx++; }

    if (setClauses.length > 0) {
      values.push(id);
      await client.query(
        `UPDATE checklist_vorlagen SET ${setClauses.join(', ')} WHERE id = $${idx}`,
        values
      );
    }

    // Replace junction rows if any array key is present
    const hasJunctionData = 'fahrzeug_typ_ids' in data || 'fahrzeug_ids' in data
      || 'ausruestung_typ_ids' in data || 'ausruestung_ids' in data;
    if (hasJunctionData) {
      await deleteJunctionRows(client, id);
      await insertJunctionRows(client, id, {
        fahrzeug_typ_ids: data.fahrzeug_typ_ids ?? [],
        fahrzeug_ids: data.fahrzeug_ids ?? [],
        ausruestung_typ_ids: data.ausruestung_typ_ids ?? [],
        ausruestung_ids: data.ausruestung_ids ?? [],
      });
    }

    await client.query('COMMIT');
    return getVorlageById(id);
  } catch (error) {
    await client.query('ROLLBACK').catch(() => {});
    logger.error('ChecklistService.updateVorlage failed', { error, id });
    throw new Error('Vorlage konnte nicht aktualisiert werden');
  } finally {
    client.release();
  }
}

async function deleteVorlage(id: number) {
  try {
    const result = await pool.query(
      `DELETE FROM checklist_vorlagen WHERE id = $1 RETURNING *`,
      [id]
    );
    return result.rows[0] || null;
  } catch (error) {
    logger.error('ChecklistService.deleteVorlage failed', { error, id });
    throw new Error('Vorlage konnte nicht gelöscht werden');
  }
}

// ---------------------------------------------------------------------------
// Vorlage Items (Template line items)
// ---------------------------------------------------------------------------

async function getVorlageItems(vorlageId: number) {
  try {
    const result = await pool.query(
      `SELECT * FROM checklist_vorlage_items WHERE vorlage_id = $1 ORDER BY sort_order ASC, id ASC`,
      [vorlageId]
    );
    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getVorlageItems failed', { error, vorlageId });
    throw new Error('Vorlage-Items konnten nicht geladen werden');
  }
}

async function addVorlageItem(vorlageId: number, data: {
  bezeichnung: string;
  beschreibung?: string | null;
  pflicht?: boolean;
  sort_order?: number;
  parent_item_id?: number | null;
}) {
  try {
    const result = await pool.query(
      `INSERT INTO checklist_vorlage_items (vorlage_id, bezeichnung, beschreibung, pflicht, sort_order, parent_item_id)
       VALUES ($1, $2, $3, $4, $5, $6)
       RETURNING *`,
      [vorlageId, data.bezeichnung, data.beschreibung ?? null, data.pflicht ?? true, data.sort_order ?? 0, data.parent_item_id ?? null]
    );
    return result.rows[0];
  } catch (error) {
    logger.error('ChecklistService.addVorlageItem failed', { error, vorlageId });
    throw new Error('Vorlage-Item konnte nicht erstellt werden');
  }
}

async function updateVorlageItem(id: number, data: {
  bezeichnung?: string;
  beschreibung?: string | null;
  pflicht?: boolean;
  sort_order?: number;
}) {
  try {
    const setClauses: string[] = [];
    const values: any[] = [];
    let idx = 1;

    if (data.bezeichnung !== undefined) { setClauses.push(`bezeichnung = $${idx}`); values.push(data.bezeichnung); idx++; }
    if ('beschreibung' in data) { setClauses.push(`beschreibung = $${idx}`); values.push(data.beschreibung); idx++; }
    if (data.pflicht !== undefined) { setClauses.push(`pflicht = $${idx}`); values.push(data.pflicht); idx++; }
    if (data.sort_order !== undefined) { setClauses.push(`sort_order = $${idx}`); values.push(data.sort_order); idx++; }

    if (setClauses.length === 0) {
      const r = await pool.query(`SELECT * FROM checklist_vorlage_items WHERE id = $1`, [id]);
      return r.rows[0] || null;
    }

    values.push(id);
    const result = await pool.query(
      `UPDATE checklist_vorlage_items SET ${setClauses.join(', ')} WHERE id = $${idx} RETURNING *`,
      values
    );
    return result.rows[0] || null;
  } catch (error) {
    logger.error('ChecklistService.updateVorlageItem failed', { error, id });
    throw new Error('Vorlage-Item konnte nicht aktualisiert werden');
  }
}

async function deleteVorlageItem(id: number) {
  try {
    const result = await pool.query(
      `DELETE FROM checklist_vorlage_items WHERE id = $1 RETURNING *`,
      [id]
    );
    return result.rows[0] || null;
  } catch (error) {
    logger.error('ChecklistService.deleteVorlageItem failed', { error, id });
    throw new Error('Vorlage-Item konnte nicht gelöscht werden');
  }
}

// ---------------------------------------------------------------------------
// Fahrzeug-spezifische Items
// ---------------------------------------------------------------------------

async function getVehicleItems(fahrzeugId: string) {
  try {
    const result = await pool.query(
      `SELECT * FROM fahrzeug_checklist_items WHERE fahrzeug_id = $1 AND aktiv = true ORDER BY sort_order ASC, id ASC`,
      [fahrzeugId]
    );
    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getVehicleItems failed', { error, fahrzeugId });
    throw new Error('Fahrzeug-Items konnten nicht geladen werden');
  }
}

async function addVehicleItem(fahrzeugId: string, data: {
  bezeichnung: string;
  beschreibung?: string | null;
  pflicht?: boolean;
  sort_order?: number;
}) {
  try {
    const result = await pool.query(
      `INSERT INTO fahrzeug_checklist_items (fahrzeug_id, bezeichnung, beschreibung, pflicht, sort_order)
       VALUES ($1, $2, $3, $4, $5)
       RETURNING *`,
      [fahrzeugId, data.bezeichnung, data.beschreibung ?? null, data.pflicht ?? true, data.sort_order ?? 0]
    );
    return result.rows[0];
  } catch (error) {
    logger.error('ChecklistService.addVehicleItem failed', { error, fahrzeugId });
    throw new Error('Fahrzeug-Item konnte nicht erstellt werden');
  }
}

async function updateVehicleItem(id: number, data: {
  bezeichnung?: string;
  beschreibung?: string | null;
  pflicht?: boolean;
  sort_order?: number;
  aktiv?: boolean;
}) {
  try {
    const setClauses: string[] = [];
    const values: any[] = [];
    let idx = 1;

    if (data.bezeichnung !== undefined) { setClauses.push(`bezeichnung = $${idx}`); values.push(data.bezeichnung); idx++; }
    if ('beschreibung' in data) { setClauses.push(`beschreibung = $${idx}`); values.push(data.beschreibung); idx++; }
    if (data.pflicht !== undefined) { setClauses.push(`pflicht = $${idx}`); values.push(data.pflicht); idx++; }
    if (data.sort_order !== undefined) { setClauses.push(`sort_order = $${idx}`); values.push(data.sort_order); idx++; }
    if (data.aktiv !== undefined) { setClauses.push(`aktiv = $${idx}`); values.push(data.aktiv); idx++; }

    if (setClauses.length === 0) {
      const r = await pool.query(`SELECT * FROM fahrzeug_checklist_items WHERE id = $1`, [id]);
      return r.rows[0] || null;
    }

    values.push(id);
    const result = await pool.query(
      `UPDATE fahrzeug_checklist_items SET ${setClauses.join(', ')} WHERE id = $${idx} RETURNING *`,
      values
    );
    return result.rows[0] || null;
  } catch (error) {
    logger.error('ChecklistService.updateVehicleItem failed', { error, id });
    throw new Error('Fahrzeug-Item konnte nicht aktualisiert werden');
  }
}

async function deleteVehicleItem(id: number) {
  try {
    const result = await pool.query(
      `UPDATE fahrzeug_checklist_items SET aktiv = false WHERE id = $1 RETURNING *`,
      [id]
    );
    return result.rows[0] || null;
  } catch (error) {
    logger.error('ChecklistService.deleteVehicleItem failed', { error, id });
    throw new Error('Fahrzeug-Item konnte nicht deaktiviert werden');
  }
}

// ---------------------------------------------------------------------------
// Ausrüstung-spezifische Items
// ---------------------------------------------------------------------------

async function getEquipmentItems(ausruestungId: string) {
  try {
    const result = await pool.query(
      `SELECT * FROM ausruestung_checklist_items WHERE ausruestung_id = $1 AND aktiv = true ORDER BY sort_order ASC, id ASC`,
      [ausruestungId]
    );
    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getEquipmentItems failed', { error, ausruestungId });
    throw new Error('Ausrüstungs-Items konnten nicht geladen werden');
  }
}

async function addEquipmentItem(ausruestungId: string, data: {
  bezeichnung: string;
  beschreibung?: string | null;
  pflicht?: boolean;
  sort_order?: number;
}) {
  try {
    const result = await pool.query(
      `INSERT INTO ausruestung_checklist_items (ausruestung_id, bezeichnung, beschreibung, pflicht, sort_order)
       VALUES ($1, $2, $3, $4, $5)
       RETURNING *`,
      [ausruestungId, data.bezeichnung, data.beschreibung ?? null, data.pflicht ?? true, data.sort_order ?? 0]
    );
    return result.rows[0];
  } catch (error) {
    logger.error('ChecklistService.addEquipmentItem failed', { error, ausruestungId });
    throw new Error('Ausrüstungs-Item konnte nicht erstellt werden');
  }
}

async function updateEquipmentItem(id: number, data: {
  bezeichnung?: string;
  beschreibung?: string | null;
  pflicht?: boolean;
  sort_order?: number;
  aktiv?: boolean;
}) {
  try {
    const setClauses: string[] = [];
    const values: any[] = [];
    let idx = 1;

    if (data.bezeichnung !== undefined) { setClauses.push(`bezeichnung = $${idx}`); values.push(data.bezeichnung); idx++; }
    if ('beschreibung' in data) { setClauses.push(`beschreibung = $${idx}`); values.push(data.beschreibung); idx++; }
    if (data.pflicht !== undefined) { setClauses.push(`pflicht = $${idx}`); values.push(data.pflicht); idx++; }
    if (data.sort_order !== undefined) { setClauses.push(`sort_order = $${idx}`); values.push(data.sort_order); idx++; }
    if (data.aktiv !== undefined) { setClauses.push(`aktiv = $${idx}`); values.push(data.aktiv); idx++; }

    if (setClauses.length === 0) {
      const r = await pool.query(`SELECT * FROM ausruestung_checklist_items WHERE id = $1`, [id]);
      return r.rows[0] || null;
    }

    values.push(id);
    const result = await pool.query(
      `UPDATE ausruestung_checklist_items SET ${setClauses.join(', ')} WHERE id = $${idx} RETURNING *`,
      values
    );
    return result.rows[0] || null;
  } catch (error) {
    logger.error('ChecklistService.updateEquipmentItem failed', { error, id });
    throw new Error('Ausrüstungs-Item konnte nicht aktualisiert werden');
  }
}

async function deleteEquipmentItem(id: number) {
  try {
    const result = await pool.query(
      `UPDATE ausruestung_checklist_items SET aktiv = false WHERE id = $1 RETURNING *`,
      [id]
    );
    return result.rows[0] || null;
  } catch (error) {
    logger.error('ChecklistService.deleteEquipmentItem failed', { error, id });
    throw new Error('Ausrüstungs-Item konnte nicht deaktiviert werden');
  }
}

// ---------------------------------------------------------------------------
// Templates for a specific vehicle (via junction tables)
// ---------------------------------------------------------------------------

async function getTemplatesForVehicle(fahrzeugId: string) {
  try {
    const result = await pool.query(
      `SELECT DISTINCT v.*,
              ${JUNCTION_SUBQUERIES}
       FROM checklist_vorlagen v
       WHERE v.aktiv = true
         AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = v.id)
         AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung WHERE vorlage_id = v.id)
         AND (
           EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeuge cvf WHERE cvf.vorlage_id = v.id AND cvf.fahrzeug_id = $1)
           OR EXISTS (
             SELECT 1 FROM checklist_vorlage_fahrzeug_typen cvft
             WHERE cvft.vorlage_id = v.id
               AND cvft.fahrzeug_typ_id IN (SELECT fahrzeug_typ_id FROM fahrzeug_fahrzeug_typen WHERE fahrzeug_id = $1)
           )
           OR (
             NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeug_typen WHERE vorlage_id = v.id)
             AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeuge WHERE vorlage_id = v.id)
             AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = v.id)
             AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung WHERE vorlage_id = v.id)
           )
         )
       ORDER BY v.name ASC`,
      [fahrzeugId]
    );

    // Attach items to each template
    for (const vorlage of result.rows) {
      const items = await pool.query(
        `SELECT * FROM checklist_vorlage_items WHERE vorlage_id = $1 ORDER BY sort_order ASC, id ASC`,
        [vorlage.id]
      );
      vorlage.items = items.rows;
    }

    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getTemplatesForVehicle failed', { error, fahrzeugId });
    throw new Error('Checklisten für Fahrzeug konnten nicht geladen werden');
  }
}

// ---------------------------------------------------------------------------
// Templates for a specific equipment item (via junction tables)
// ---------------------------------------------------------------------------

async function getTemplatesForEquipment(ausruestungId: string) {
  try {
    const result = await pool.query(
      `SELECT DISTINCT v.*,
              ${JUNCTION_SUBQUERIES}
       FROM checklist_vorlagen v
       WHERE v.aktiv = true
         AND (
           EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung cva WHERE cva.vorlage_id = v.id AND cva.ausruestung_id = $1)
           OR EXISTS (
             SELECT 1 FROM checklist_vorlage_ausruestung_typen cvat
             WHERE cvat.vorlage_id = v.id
               AND cvat.ausruestung_typ_id IN (SELECT ausruestung_typ_id FROM ausruestung_ausruestung_typen WHERE ausruestung_id = $1)
           )
           OR (
             ${GLOBAL_TEMPLATE_CONDITION}
           )
         )
       ORDER BY v.name ASC`,
      [ausruestungId]
    );

    // Attach items to each template
    for (const vorlage of result.rows) {
      const items = await pool.query(
        `SELECT * FROM checklist_vorlage_items WHERE vorlage_id = $1 ORDER BY sort_order ASC, id ASC`,
        [vorlage.id]
      );
      vorlage.items = items.rows;
    }

    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getTemplatesForEquipment failed', { error, ausruestungId });
    throw new Error('Checklisten für Ausrüstung konnten nicht geladen werden');
  }
}

// ---------------------------------------------------------------------------
// Overview Items (vehicles + equipment with open checklists)
// ---------------------------------------------------------------------------

async function getOverviewItems() {
  try {
    // All vehicles with their assigned templates (direct, by type, or global)
    const vehiclesResult = await pool.query(`
      SELECT f.id, COALESCE(f.bezeichnung, f.kurzname) AS name,
             json_agg(DISTINCT jsonb_build_object(
               'vorlage_id', cv.id,
               'vorlage_name', cv.name,
               'intervall', cv.intervall,
               'next_due', cf.naechste_faellig_am
             )) AS checklists
      FROM fahrzeuge f
      JOIN checklist_vorlagen cv ON cv.aktiv = true
        AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = cv.id)
        AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung WHERE vorlage_id = cv.id)
        AND (
          EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeuge cvf WHERE cvf.vorlage_id = cv.id AND cvf.fahrzeug_id = f.id)
          OR EXISTS (
            SELECT 1 FROM checklist_vorlage_fahrzeug_typen cvft
            WHERE cvft.vorlage_id = cv.id
              AND cvft.fahrzeug_typ_id IN (SELECT fahrzeug_typ_id FROM fahrzeug_fahrzeug_typen WHERE fahrzeug_id = f.id)
          )
          OR (
            NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeug_typen WHERE vorlage_id = cv.id)
            AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeuge WHERE vorlage_id = cv.id)
            AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = cv.id)
            AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung WHERE vorlage_id = cv.id)
          )
        )
      LEFT JOIN checklist_faelligkeit cf ON cf.vorlage_id = cv.id AND cf.fahrzeug_id = f.id
      WHERE f.deleted_at IS NULL
      GROUP BY f.id, f.bezeichnung, f.kurzname
      ORDER BY f.bezeichnung ASC, f.kurzname ASC
    `);

    // All equipment with their assigned templates
    const equipmentResult = await pool.query(`
      SELECT a.id, a.bezeichnung AS name,
             json_agg(DISTINCT jsonb_build_object(
               'vorlage_id', cv.id,
               'vorlage_name', cv.name,
               'intervall', cv.intervall,
               'next_due', cf.naechste_faellig_am
             )) AS checklists
      FROM ausruestung a
      JOIN checklist_vorlagen cv ON cv.aktiv = true
        AND (
          EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung cva WHERE cva.vorlage_id = cv.id AND cva.ausruestung_id = a.id)
          OR EXISTS (
            SELECT 1 FROM checklist_vorlage_ausruestung_typen cvat
            WHERE cvat.vorlage_id = cv.id
              AND cvat.ausruestung_typ_id IN (SELECT ausruestung_typ_id FROM ausruestung_ausruestung_typen WHERE ausruestung_id = a.id)
          )
          OR (
            NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeug_typen WHERE vorlage_id = cv.id)
            AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_fahrzeuge WHERE vorlage_id = cv.id)
            AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung_typen WHERE vorlage_id = cv.id)
            AND NOT EXISTS (SELECT 1 FROM checklist_vorlage_ausruestung WHERE vorlage_id = cv.id)
          )
        )
      LEFT JOIN checklist_faelligkeit cf ON cf.vorlage_id = cv.id AND cf.ausruestung_id = a.id
      WHERE a.deleted_at IS NULL
      GROUP BY a.id, a.bezeichnung
      ORDER BY a.bezeichnung ASC
    `);

    return {
      vehicles: vehiclesResult.rows,
      equipment: equipmentResult.rows,
    };
  } catch (error) {
    logger.error('ChecklistService.getOverviewItems failed', { error });
    throw new Error('Übersichtsdaten konnten nicht geladen werden');
  }
}

// ---------------------------------------------------------------------------
// Ausführungen (Executions)
// ---------------------------------------------------------------------------

async function startExecution(fahrzeugId: string | null, vorlageId: number, userId: string, ausruestungId?: string | null) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');

    // Create the execution record
    const execResult = await client.query(
      `INSERT INTO checklist_ausfuehrungen (fahrzeug_id, ausruestung_id, vorlage_id, ausgefuehrt_von)
       VALUES ($1, $2, $3, $4)
       RETURNING *`,
      [fahrzeugId || null, ausruestungId || null, vorlageId, userId]
    );
    const execution = execResult.rows[0];

    // Copy template items into execution items (two-pass to preserve parent-child hierarchy)
    const vorlageItems = await client.query(
      `SELECT * FROM checklist_vorlage_items WHERE vorlage_id = $1 ORDER BY sort_order ASC, id ASC`,
      [vorlageId]
    );
    // First pass: insert all items, record the vorlage_item_id → ausfuehrung_item_id mapping
    const vorlageToAusfuehrungId = new Map<number, number>();
    for (const item of vorlageItems.rows) {
      const inserted = await client.query(
        `INSERT INTO checklist_ausfuehrung_items (ausfuehrung_id, vorlage_item_id, bezeichnung)
         VALUES ($1, $2, $3)
         RETURNING id`,
        [execution.id, item.id, item.bezeichnung]
      );
      vorlageToAusfuehrungId.set(item.id, inserted.rows[0].id);
    }
    // Second pass: set parent_ausfuehrung_item_id for items that have a parent
    for (const item of vorlageItems.rows) {
      if (item.parent_item_id != null) {
        const parentAusfuehrungId = vorlageToAusfuehrungId.get(item.parent_item_id);
        const childAusfuehrungId = vorlageToAusfuehrungId.get(item.id);
        if (parentAusfuehrungId && childAusfuehrungId) {
          await client.query(
            `UPDATE checklist_ausfuehrung_items SET parent_ausfuehrung_item_id = $1 WHERE id = $2`,
            [parentAusfuehrungId, childAusfuehrungId]
          );
        }
      }
    }

    // Copy entity-specific items (vehicle or equipment)
    if (ausruestungId) {
      const equipmentItems = await client.query(
        `SELECT * FROM ausruestung_checklist_items WHERE ausruestung_id = $1 AND aktiv = true ORDER BY sort_order ASC, id ASC`,
        [ausruestungId]
      );
      for (const item of equipmentItems.rows) {
        await client.query(
          `INSERT INTO checklist_ausfuehrung_items (ausfuehrung_id, ausruestung_item_id, bezeichnung)
           VALUES ($1, $2, $3)`,
          [execution.id, item.id, item.bezeichnung]
        );
      }
    } else if (fahrzeugId) {
      const vehicleItems = await client.query(
        `SELECT * FROM fahrzeug_checklist_items WHERE fahrzeug_id = $1 AND aktiv = true ORDER BY sort_order ASC, id ASC`,
        [fahrzeugId]
      );
      for (const item of vehicleItems.rows) {
        await client.query(
          `INSERT INTO checklist_ausfuehrung_items (ausfuehrung_id, fahrzeug_item_id, bezeichnung)
           VALUES ($1, $2, $3)`,
          [execution.id, item.id, item.bezeichnung]
        );
      }
    }

    await client.query('COMMIT');

    // Fetch the complete execution with items
    return getExecutionById(execution.id);
  } catch (error) {
    await client.query('ROLLBACK').catch(() => {});
    logger.error('ChecklistService.startExecution failed', { error, fahrzeugId, vorlageId });
    throw new Error('Checklist-Ausführung konnte nicht gestartet werden');
  } finally {
    client.release();
  }
}

async function getExecutionById(id: string) {
  try {
    const execResult = await pool.query(
      `SELECT a.*,
              f.bezeichnung AS fahrzeug_name, f.kurzname AS fahrzeug_kurzname,
              ar.bezeichnung AS ausruestung_name,
              v.name AS vorlage_name,
              u1.name AS ausgefuehrt_von_name,
              u2.name AS freigegeben_von_name
       FROM checklist_ausfuehrungen a
       LEFT JOIN fahrzeuge f ON f.id = a.fahrzeug_id
       LEFT JOIN ausruestung ar ON ar.id = a.ausruestung_id
       LEFT JOIN checklist_vorlagen v ON v.id = a.vorlage_id
       LEFT JOIN users u1 ON u1.id = a.ausgefuehrt_von
       LEFT JOIN users u2 ON u2.id = a.freigegeben_von
       WHERE a.id = $1`,
      [id]
    );
    if (execResult.rows.length === 0) return null;

    const execution = execResult.rows[0];
    const itemsResult = await pool.query(
      `SELECT * FROM checklist_ausfuehrung_items WHERE ausfuehrung_id = $1 ORDER BY id ASC`,
      [id]
    );
    execution.items = itemsResult.rows;
    return execution;
  } catch (error) {
    logger.error('ChecklistService.getExecutionById failed', { error, id });
    throw new Error('Ausführung konnte nicht geladen werden');
  }
}

async function submitExecution(
  id: string,
  items: Array<{ itemId: number; ergebnis: string; kommentar?: string }>,
  notizen: string | null,
  _userId: string,
) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');

    // Update each item's result
    for (const item of items) {
      await client.query(
        `UPDATE checklist_ausfuehrung_items SET ergebnis = $1, kommentar = $2 WHERE id = $3 AND ausfuehrung_id = $4`,
        [item.ergebnis, item.kommentar ?? null, item.itemId, id]
      );
    }

    // Check if all pflicht items have ergebnis = 'ok'
    // Exclude parent items (those that have subitems) — their children carry the pflicht flag
    const pflichtCheck = await client.query(
      `SELECT ai.id, ai.ergebnis, ai.vorlage_item_id, ai.fahrzeug_item_id, ai.ausruestung_item_id
       FROM checklist_ausfuehrung_items ai
       LEFT JOIN checklist_vorlage_items vi ON vi.id = ai.vorlage_item_id
       LEFT JOIN fahrzeug_checklist_items fi ON fi.id = ai.fahrzeug_item_id
       LEFT JOIN ausruestung_checklist_items aci ON aci.id = ai.ausruestung_item_id
       WHERE ai.ausfuehrung_id = $1
         AND (COALESCE(vi.pflicht, fi.pflicht, aci.pflicht, true) = true)
         AND NOT EXISTS (
           SELECT 1 FROM checklist_ausfuehrung_items child
           WHERE child.parent_ausfuehrung_item_id = ai.id
         )`,
      [id]
    );

    const allPflichtOk = pflichtCheck.rows.every((r: any) => r.ergebnis === 'ok');
    const newStatus = allPflichtOk ? 'abgeschlossen' : 'unvollstaendig';

    await client.query(
      `UPDATE checklist_ausfuehrungen SET status = $1, ausgefuehrt_am = NOW(), notizen = $2 WHERE id = $3`,
      [newStatus, notizen, id]
    );

    // Update checklist_faelligkeit if completed
    if (allPflichtOk) {
      const exec = await client.query(`SELECT vorlage_id, fahrzeug_id, ausruestung_id FROM checklist_ausfuehrungen WHERE id = $1`, [id]);
      if (exec.rows.length > 0) {
        const { vorlage_id, fahrzeug_id, ausruestung_id } = exec.rows[0];
        const vorlage = await client.query(`SELECT intervall, intervall_tage FROM checklist_vorlagen WHERE id = $1`, [vorlage_id]);
        if (vorlage.rows.length > 0) {
          const nextDue = calculateNextDueDate(vorlage.rows[0].intervall, vorlage.rows[0].intervall_tage);
          if (nextDue) {
            if (ausruestung_id) {
              await client.query(
                `INSERT INTO checklist_faelligkeit (ausruestung_id, vorlage_id, naechste_faellig_am, letzte_ausfuehrung_id)
                 VALUES ($1, $2, $3, $4)
                 ON CONFLICT (vorlage_id, ausruestung_id) WHERE ausruestung_id IS NOT NULL AND fahrzeug_id IS NULL
                 DO UPDATE SET naechste_faellig_am = $3, letzte_ausfuehrung_id = $4`,
                [ausruestung_id, vorlage_id, nextDue, id]
              );
            } else if (fahrzeug_id) {
              await client.query(
                `INSERT INTO checklist_faelligkeit (fahrzeug_id, vorlage_id, naechste_faellig_am, letzte_ausfuehrung_id)
                 VALUES ($1, $2, $3, $4)
                 ON CONFLICT (vorlage_id, fahrzeug_id) WHERE fahrzeug_id IS NOT NULL AND ausruestung_id IS NULL
                 DO UPDATE SET naechste_faellig_am = $3, letzte_ausfuehrung_id = $4`,
                [fahrzeug_id, vorlage_id, nextDue, id]
              );
            }
          }
        }
      }
    }

    await client.query('COMMIT');
    return getExecutionById(id);
  } catch (error) {
    await client.query('ROLLBACK').catch(() => {});
    logger.error('ChecklistService.submitExecution failed', { error, id });
    throw new Error('Ausführung konnte nicht abgeschlossen werden');
  } finally {
    client.release();
  }
}

async function approveExecution(id: string, userId: string) {
  try {
    const result = await pool.query(
      `UPDATE checklist_ausfuehrungen
       SET status = 'freigegeben', freigegeben_von = $1, freigegeben_am = NOW()
       WHERE id = $2 AND status IN ('abgeschlossen', 'unvollstaendig')
       RETURNING *`,
      [userId, id]
    );
    if (result.rows.length === 0) return null;
    return getExecutionById(id);
  } catch (error) {
    logger.error('ChecklistService.approveExecution failed', { error, id });
    throw new Error('Freigabe konnte nicht erteilt werden');
  }
}

async function getExecutions(filter?: { fahrzeugId?: string; ausruestungId?: string; vorlageId?: number; status?: string }) {
  try {
    const conditions: string[] = [];
    const values: any[] = [];
    let idx = 1;

    if (filter?.fahrzeugId) {
      conditions.push(`a.fahrzeug_id = $${idx}`);
      values.push(filter.fahrzeugId);
      idx++;
    }
    if (filter?.ausruestungId) {
      conditions.push(`a.ausruestung_id = $${idx}`);
      values.push(filter.ausruestungId);
      idx++;
    }
    if (filter?.vorlageId) {
      conditions.push(`a.vorlage_id = $${idx}`);
      values.push(filter.vorlageId);
      idx++;
    }
    if (filter?.status) {
      conditions.push(`a.status = $${idx}`);
      values.push(filter.status);
      idx++;
    }

    const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
    const result = await pool.query(
      `SELECT a.*,
              f.bezeichnung AS fahrzeug_name, f.kurzname AS fahrzeug_kurzname,
              ar.bezeichnung AS ausruestung_name,
              v.name AS vorlage_name,
              u1.name AS ausgefuehrt_von_name,
              u2.name AS freigegeben_von_name
       FROM checklist_ausfuehrungen a
       LEFT JOIN fahrzeuge f ON f.id = a.fahrzeug_id
       LEFT JOIN ausruestung ar ON ar.id = a.ausruestung_id
       LEFT JOIN checklist_vorlagen v ON v.id = a.vorlage_id
       LEFT JOIN users u1 ON u1.id = a.ausgefuehrt_von
       LEFT JOIN users u2 ON u2.id = a.freigegeben_von
       ${where}
       ORDER BY a.created_at DESC`,
      values
    );
    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getExecutions failed', { error });
    throw new Error('Ausführungen konnten nicht geladen werden');
  }
}

// ---------------------------------------------------------------------------
// Fälligkeiten (Due dates)
// ---------------------------------------------------------------------------

async function getOverdueChecklists() {
  try {
    const result = await pool.query(`
      SELECT cf.*,
             f.bezeichnung AS fahrzeug_name, f.kurzname AS fahrzeug_kurzname,
             ar.bezeichnung AS ausruestung_name,
             v.name AS vorlage_name
      FROM checklist_faelligkeit cf
      LEFT JOIN fahrzeuge f ON f.id = cf.fahrzeug_id AND f.deleted_at IS NULL
      LEFT JOIN ausruestung ar ON ar.id = cf.ausruestung_id
      JOIN checklist_vorlagen v ON v.id = cf.vorlage_id AND v.aktiv = true
      WHERE cf.naechste_faellig_am <= CURRENT_DATE
        AND (cf.fahrzeug_id IS NOT NULL OR cf.ausruestung_id IS NOT NULL)
        AND (cf.fahrzeug_id IS NULL OR f.id IS NOT NULL)
      ORDER BY cf.naechste_faellig_am ASC
    `);
    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getOverdueChecklists failed', { error });
    throw new Error('Überfällige Checklisten konnten nicht geladen werden');
  }
}

async function getDueChecklists(fahrzeugId: string) {
  try {
    const result = await pool.query(
      `SELECT cf.*, v.name AS vorlage_name, v.intervall, v.intervall_tage
       FROM checklist_faelligkeit cf
       JOIN checklist_vorlagen v ON v.id = cf.vorlage_id AND v.aktiv = true
       WHERE cf.fahrzeug_id = $1
       ORDER BY cf.naechste_faellig_am ASC`,
      [fahrzeugId]
    );
    return result.rows;
  } catch (error) {
    logger.error('ChecklistService.getDueChecklists failed', { error, fahrzeugId });
    throw new Error('Fälligkeiten konnten nicht geladen werden');
  }
}

export default {
  getVorlagen,
  getVorlageById,
  createVorlage,
  updateVorlage,
  deleteVorlage,
  getVorlageItems,
  addVorlageItem,
  updateVorlageItem,
  deleteVorlageItem,
  getVehicleItems,
  addVehicleItem,
  updateVehicleItem,
  deleteVehicleItem,
  getEquipmentItems,
  addEquipmentItem,
  updateEquipmentItem,
  deleteEquipmentItem,
  getTemplatesForVehicle,
  getTemplatesForEquipment,
  getOverviewItems,
  startExecution,
  getExecutionById,
  submitExecution,
  approveExecution,
  getExecutions,
  getOverdueChecklists,
  getDueChecklists,
};
