/**
 * 화면 임베딩 및 데이터 전달 시스템 컨트롤러
 */

import { Request, Response } from "express";
import { getPool } from "../database/db";
import { logger } from "../utils/logger";
import { AuthenticatedRequest } from "../types/auth";

const pool = getPool();

// ============================================
// 1. 화면 임베딩 API
// ============================================

/**
 * 화면 임베딩 목록 조회
 * GET /api/screen-embedding?parentScreenId=1
 */
export async function getScreenEmbeddings(req: AuthenticatedRequest, res: Response) {
  try {
    const { parentScreenId } = req.query;
    const companyCode = req.user!.companyCode;

    if (!parentScreenId) {
      return res.status(400).json({
        success: false,
        message: "부모 화면 ID가 필요합니다.",
      });
    }

    const query = `
      SELECT 
        se.*,
        ps.screen_name as parent_screen_name,
        cs.screen_name as child_screen_name
      FROM screen_embedding se
      LEFT JOIN screen_definitions ps ON se.parent_screen_id = ps.screen_id
      LEFT JOIN screen_definitions cs ON se.child_screen_id = cs.screen_id
      WHERE se.parent_screen_id = $1
        AND se.company_code = $2
      ORDER BY se.position, se.created_at
    `;

    const result = await pool.query(query, [parentScreenId, companyCode]);

    logger.info("화면 임베딩 목록 조회", {
      companyCode,
      parentScreenId,
      count: result.rowCount,
    });

    return res.json({
      success: true,
      data: result.rows,
    });
  } catch (error: any) {
    logger.error("화면 임베딩 목록 조회 실패", error);
    return res.status(500).json({
      success: false,
      message: "화면 임베딩 목록 조회 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 화면 임베딩 상세 조회
 * GET /api/screen-embedding/:id
 */
export async function getScreenEmbeddingById(req: AuthenticatedRequest, res: Response) {
  try {
    const { id } = req.params;
    const companyCode = req.user!.companyCode;

    const query = `
      SELECT 
        se.*,
        ps.screen_name as parent_screen_name,
        cs.screen_name as child_screen_name
      FROM screen_embedding se
      LEFT JOIN screen_definitions ps ON se.parent_screen_id = ps.screen_id
      LEFT JOIN screen_definitions cs ON se.child_screen_id = cs.screen_id
      WHERE se.id = $1
        AND se.company_code = $2
    `;

    const result = await pool.query(query, [id, companyCode]);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "화면 임베딩 설정을 찾을 수 없습니다.",
      });
    }

    logger.info("화면 임베딩 상세 조회", { companyCode, id });

    return res.json({
      success: true,
      data: result.rows[0],
    });
  } catch (error: any) {
    logger.error("화면 임베딩 상세 조회 실패", error);
    return res.status(500).json({
      success: false,
      message: "화면 임베딩 상세 조회 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 화면 임베딩 생성
 * POST /api/screen-embedding
 */
export async function createScreenEmbedding(req: AuthenticatedRequest, res: Response) {
  try {
    const {
      parentScreenId,
      childScreenId,
      position,
      mode,
      config = {},
    } = req.body;
    const companyCode = req.user!.companyCode;
    const userId = req.user!.userId;

    // 필수 필드 검증
    if (!parentScreenId || !childScreenId || !position || !mode) {
      return res.status(400).json({
        success: false,
        message: "필수 필드가 누락되었습니다.",
      });
    }

    const query = `
      INSERT INTO screen_embedding (
        parent_screen_id, child_screen_id, position, mode,
        config, company_code, created_by, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
      RETURNING *
    `;

    const result = await pool.query(query, [
      parentScreenId,
      childScreenId,
      position,
      mode,
      JSON.stringify(config),
      companyCode,
      userId,
    ]);

    logger.info("화면 임베딩 생성", {
      companyCode,
      userId,
      id: result.rows[0].id,
    });

    return res.status(201).json({
      success: true,
      data: result.rows[0],
    });
  } catch (error: any) {
    logger.error("화면 임베딩 생성 실패", error);

    // 유니크 제약조건 위반
    if (error.code === "23505") {
      return res.status(409).json({
        success: false,
        message: "이미 동일한 임베딩 설정이 존재합니다.",
      });
    }

    return res.status(500).json({
      success: false,
      message: "화면 임베딩 생성 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 화면 임베딩 수정
 * PUT /api/screen-embedding/:id
 */
export async function updateScreenEmbedding(req: AuthenticatedRequest, res: Response) {
  try {
    const { id } = req.params;
    const { position, mode, config } = req.body;
    const companyCode = req.user!.companyCode;

    const updates: string[] = [];
    const values: any[] = [];
    let paramIndex = 1;

    if (position) {
      updates.push(`position = $${paramIndex++}`);
      values.push(position);
    }

    if (mode) {
      updates.push(`mode = $${paramIndex++}`);
      values.push(mode);
    }

    if (config) {
      updates.push(`config = $${paramIndex++}`);
      values.push(JSON.stringify(config));
    }

    if (updates.length === 0) {
      return res.status(400).json({
        success: false,
        message: "수정할 내용이 없습니다.",
      });
    }

    updates.push(`updated_at = NOW()`);

    values.push(id, companyCode);

    const query = `
      UPDATE screen_embedding
      SET ${updates.join(", ")}
      WHERE id = $${paramIndex++}
        AND company_code = $${paramIndex++}
      RETURNING *
    `;

    const result = await pool.query(query, values);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "화면 임베딩 설정을 찾을 수 없습니다.",
      });
    }

    logger.info("화면 임베딩 수정", { companyCode, id });

    return res.json({
      success: true,
      data: result.rows[0],
    });
  } catch (error: any) {
    logger.error("화면 임베딩 수정 실패", error);
    return res.status(500).json({
      success: false,
      message: "화면 임베딩 수정 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 화면 임베딩 삭제
 * DELETE /api/screen-embedding/:id
 */
export async function deleteScreenEmbedding(req: AuthenticatedRequest, res: Response) {
  try {
    const { id } = req.params;
    const companyCode = req.user!.companyCode;

    const query = `
      DELETE FROM screen_embedding
      WHERE id = $1 AND company_code = $2
      RETURNING id
    `;

    const result = await pool.query(query, [id, companyCode]);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "화면 임베딩 설정을 찾을 수 없습니다.",
      });
    }

    logger.info("화면 임베딩 삭제", { companyCode, id });

    return res.json({
      success: true,
      message: "화면 임베딩이 삭제되었습니다.",
    });
  } catch (error: any) {
    logger.error("화면 임베딩 삭제 실패", error);
    return res.status(500).json({
      success: false,
      message: "화면 임베딩 삭제 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

// ============================================
// 2. 데이터 전달 API
// ============================================

/**
 * 데이터 전달 설정 조회
 * GET /api/screen-data-transfer?sourceScreenId=1&targetScreenId=2
 */
export async function getScreenDataTransfer(req: AuthenticatedRequest, res: Response) {
  try {
    const { sourceScreenId, targetScreenId } = req.query;
    const companyCode = req.user!.companyCode;

    if (!sourceScreenId || !targetScreenId) {
      return res.status(400).json({
        success: false,
        message: "소스 화면 ID와 타겟 화면 ID가 필요합니다.",
      });
    }

    const query = `
      SELECT 
        sdt.*,
        ss.screen_name as source_screen_name,
        ts.screen_name as target_screen_name
      FROM screen_data_transfer sdt
      LEFT JOIN screen_definitions ss ON sdt.source_screen_id = ss.screen_id
      LEFT JOIN screen_definitions ts ON sdt.target_screen_id = ts.screen_id
      WHERE sdt.source_screen_id = $1
        AND sdt.target_screen_id = $2
        AND sdt.company_code = $3
    `;

    const result = await pool.query(query, [
      sourceScreenId,
      targetScreenId,
      companyCode,
    ]);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "데이터 전달 설정을 찾을 수 없습니다.",
      });
    }

    logger.info("데이터 전달 설정 조회", {
      companyCode,
      sourceScreenId,
      targetScreenId,
    });

    return res.json({
      success: true,
      data: result.rows[0],
    });
  } catch (error: any) {
    logger.error("데이터 전달 설정 조회 실패", error);
    return res.status(500).json({
      success: false,
      message: "데이터 전달 설정 조회 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 데이터 전달 설정 생성
 * POST /api/screen-data-transfer
 */
export async function createScreenDataTransfer(req: AuthenticatedRequest, res: Response) {
  try {
    const {
      sourceScreenId,
      targetScreenId,
      sourceComponentId,
      sourceComponentType,
      dataReceivers,
      buttonConfig,
    } = req.body;
    const companyCode = req.user!.companyCode;
    const userId = req.user!.userId;

    // 필수 필드 검증
    if (!sourceScreenId || !targetScreenId || !dataReceivers) {
      return res.status(400).json({
        success: false,
        message: "필수 필드가 누락되었습니다.",
      });
    }

    const query = `
      INSERT INTO screen_data_transfer (
        source_screen_id, target_screen_id, source_component_id, source_component_type,
        data_receivers, button_config, company_code, created_by, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
      RETURNING *
    `;

    const result = await pool.query(query, [
      sourceScreenId,
      targetScreenId,
      sourceComponentId,
      sourceComponentType,
      JSON.stringify(dataReceivers),
      JSON.stringify(buttonConfig || {}),
      companyCode,
      userId,
    ]);

    logger.info("데이터 전달 설정 생성", {
      companyCode,
      userId,
      id: result.rows[0].id,
    });

    return res.status(201).json({
      success: true,
      data: result.rows[0],
    });
  } catch (error: any) {
    logger.error("데이터 전달 설정 생성 실패", error);

    // 유니크 제약조건 위반
    if (error.code === "23505") {
      return res.status(409).json({
        success: false,
        message: "이미 동일한 데이터 전달 설정이 존재합니다.",
      });
    }

    return res.status(500).json({
      success: false,
      message: "데이터 전달 설정 생성 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 데이터 전달 설정 수정
 * PUT /api/screen-data-transfer/:id
 */
export async function updateScreenDataTransfer(req: AuthenticatedRequest, res: Response) {
  try {
    const { id } = req.params;
    const { dataReceivers, buttonConfig } = req.body;
    const companyCode = req.user!.companyCode;

    const updates: string[] = [];
    const values: any[] = [];
    let paramIndex = 1;

    if (dataReceivers) {
      updates.push(`data_receivers = $${paramIndex++}`);
      values.push(JSON.stringify(dataReceivers));
    }

    if (buttonConfig) {
      updates.push(`button_config = $${paramIndex++}`);
      values.push(JSON.stringify(buttonConfig));
    }

    if (updates.length === 0) {
      return res.status(400).json({
        success: false,
        message: "수정할 내용이 없습니다.",
      });
    }

    updates.push(`updated_at = NOW()`);

    values.push(id, companyCode);

    const query = `
      UPDATE screen_data_transfer
      SET ${updates.join(", ")}
      WHERE id = $${paramIndex++}
        AND company_code = $${paramIndex++}
      RETURNING *
    `;

    const result = await pool.query(query, values);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "데이터 전달 설정을 찾을 수 없습니다.",
      });
    }

    logger.info("데이터 전달 설정 수정", { companyCode, id });

    return res.json({
      success: true,
      data: result.rows[0],
    });
  } catch (error: any) {
    logger.error("데이터 전달 설정 수정 실패", error);
    return res.status(500).json({
      success: false,
      message: "데이터 전달 설정 수정 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 데이터 전달 설정 삭제
 * DELETE /api/screen-data-transfer/:id
 */
export async function deleteScreenDataTransfer(req: AuthenticatedRequest, res: Response) {
  try {
    const { id } = req.params;
    const companyCode = req.user!.companyCode;

    const query = `
      DELETE FROM screen_data_transfer
      WHERE id = $1 AND company_code = $2
      RETURNING id
    `;

    const result = await pool.query(query, [id, companyCode]);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "데이터 전달 설정을 찾을 수 없습니다.",
      });
    }

    logger.info("데이터 전달 설정 삭제", { companyCode, id });

    return res.json({
      success: true,
      message: "데이터 전달 설정이 삭제되었습니다.",
    });
  } catch (error: any) {
    logger.error("데이터 전달 설정 삭제 실패", error);
    return res.status(500).json({
      success: false,
      message: "데이터 전달 설정 삭제 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

// ============================================
// 3. 분할 패널 API
// ============================================

/**
 * 분할 패널 설정 조회
 * GET /api/screen-split-panel/:screenId
 */
export async function getScreenSplitPanel(req: AuthenticatedRequest, res: Response) {
  try {
    const { screenId } = req.params;
    const companyCode = req.user!.companyCode;

    const query = `
      SELECT 
        ssp.*,
        le.parent_screen_id as le_parent_screen_id,
        le.child_screen_id as le_child_screen_id,
        le.position as le_position,
        le.mode as le_mode,
        le.config as le_config,
        re.parent_screen_id as re_parent_screen_id,
        re.child_screen_id as re_child_screen_id,
        re.position as re_position,
        re.mode as re_mode,
        re.config as re_config,
        sdt.source_screen_id,
        sdt.target_screen_id,
        sdt.source_component_id,
        sdt.source_component_type,
        sdt.data_receivers,
        sdt.button_config
      FROM screen_split_panel ssp
      LEFT JOIN screen_embedding le ON ssp.left_embedding_id = le.id
      LEFT JOIN screen_embedding re ON ssp.right_embedding_id = re.id
      LEFT JOIN screen_data_transfer sdt ON ssp.data_transfer_id = sdt.id
      WHERE ssp.screen_id = $1
        AND ssp.company_code = $2
    `;

    const result = await pool.query(query, [screenId, companyCode]);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "분할 패널 설정을 찾을 수 없습니다.",
      });
    }

    const row = result.rows[0];

    // 데이터 구조화
    const data = {
      id: row.id,
      screenId: row.screen_id,
      leftEmbeddingId: row.left_embedding_id,
      rightEmbeddingId: row.right_embedding_id,
      dataTransferId: row.data_transfer_id,
      layoutConfig: row.layout_config,
      companyCode: row.company_code,
      createdAt: row.created_at,
      updatedAt: row.updated_at,
      leftEmbedding: row.le_child_screen_id
        ? {
            id: row.left_embedding_id,
            parentScreenId: row.le_parent_screen_id,
            childScreenId: row.le_child_screen_id,
            position: row.le_position,
            mode: row.le_mode,
            config: row.le_config,
          }
        : null,
      rightEmbedding: row.re_child_screen_id
        ? {
            id: row.right_embedding_id,
            parentScreenId: row.re_parent_screen_id,
            childScreenId: row.re_child_screen_id,
            position: row.re_position,
            mode: row.re_mode,
            config: row.re_config,
          }
        : null,
      dataTransfer: row.source_screen_id
        ? {
            id: row.data_transfer_id,
            sourceScreenId: row.source_screen_id,
            targetScreenId: row.target_screen_id,
            sourceComponentId: row.source_component_id,
            sourceComponentType: row.source_component_type,
            dataReceivers: row.data_receivers,
            buttonConfig: row.button_config,
          }
        : null,
    };

    logger.info("분할 패널 설정 조회", { companyCode, screenId });

    return res.json({
      success: true,
      data,
    });
  } catch (error: any) {
    logger.error("분할 패널 설정 조회 실패", error);
    return res.status(500).json({
      success: false,
      message: "분할 패널 설정 조회 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 분할 패널 설정 생성
 * POST /api/screen-split-panel
 */
export async function createScreenSplitPanel(req: AuthenticatedRequest, res: Response) {
  const client = await pool.connect();

  try {
    const {
      screenId,
      leftEmbedding,
      rightEmbedding,
      dataTransfer,
      layoutConfig,
    } = req.body;
    const companyCode = req.user!.companyCode;
    const userId = req.user!.userId;

    // 필수 필드 검증
    if (!screenId || !leftEmbedding || !rightEmbedding || !dataTransfer) {
      return res.status(400).json({
        success: false,
        message: "필수 필드가 누락되었습니다.",
      });
    }

    await client.query("BEGIN");

    // 1. 좌측 임베딩 생성
    const leftEmbeddingQuery = `
      INSERT INTO screen_embedding (
        parent_screen_id, child_screen_id, position, mode,
        config, company_code, created_by, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
      RETURNING id
    `;

    const leftResult = await client.query(leftEmbeddingQuery, [
      screenId,
      leftEmbedding.childScreenId,
      leftEmbedding.position,
      leftEmbedding.mode,
      JSON.stringify(leftEmbedding.config || {}),
      companyCode,
      userId,
    ]);

    const leftEmbeddingId = leftResult.rows[0].id;

    // 2. 우측 임베딩 생성
    const rightEmbeddingQuery = `
      INSERT INTO screen_embedding (
        parent_screen_id, child_screen_id, position, mode,
        config, company_code, created_by, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
      RETURNING id
    `;

    const rightResult = await client.query(rightEmbeddingQuery, [
      screenId,
      rightEmbedding.childScreenId,
      rightEmbedding.position,
      rightEmbedding.mode,
      JSON.stringify(rightEmbedding.config || {}),
      companyCode,
      userId,
    ]);

    const rightEmbeddingId = rightResult.rows[0].id;

    // 3. 데이터 전달 설정 생성
    const dataTransferQuery = `
      INSERT INTO screen_data_transfer (
        source_screen_id, target_screen_id, source_component_id, source_component_type,
        data_receivers, button_config, company_code, created_by, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
      RETURNING id
    `;

    const dataTransferResult = await client.query(dataTransferQuery, [
      dataTransfer.sourceScreenId,
      dataTransfer.targetScreenId,
      dataTransfer.sourceComponentId,
      dataTransfer.sourceComponentType,
      JSON.stringify(dataTransfer.dataReceivers),
      JSON.stringify(dataTransfer.buttonConfig || {}),
      companyCode,
      userId,
    ]);

    const dataTransferId = dataTransferResult.rows[0].id;

    // 4. 분할 패널 생성
    const splitPanelQuery = `
      INSERT INTO screen_split_panel (
        screen_id, left_embedding_id, right_embedding_id, data_transfer_id,
        layout_config, company_code, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
      RETURNING *
    `;

    const splitPanelResult = await client.query(splitPanelQuery, [
      screenId,
      leftEmbeddingId,
      rightEmbeddingId,
      dataTransferId,
      JSON.stringify(layoutConfig || {}),
      companyCode,
    ]);

    await client.query("COMMIT");

    logger.info("분할 패널 설정 생성", {
      companyCode,
      userId,
      screenId,
      id: splitPanelResult.rows[0].id,
    });

    return res.status(201).json({
      success: true,
      data: splitPanelResult.rows[0],
    });
  } catch (error: any) {
    await client.query("ROLLBACK");
    logger.error("분할 패널 설정 생성 실패", error);

    return res.status(500).json({
      success: false,
      message: "분할 패널 설정 생성 중 오류가 발생했습니다.",
      error: error.message,
    });
  } finally {
    client.release();
  }
}

/**
 * 분할 패널 설정 수정
 * PUT /api/screen-split-panel/:id
 */
export async function updateScreenSplitPanel(req: AuthenticatedRequest, res: Response) {
  try {
    const { id } = req.params;
    const { layoutConfig } = req.body;
    const companyCode = req.user!.companyCode;

    if (!layoutConfig) {
      return res.status(400).json({
        success: false,
        message: "수정할 내용이 없습니다.",
      });
    }

    const query = `
      UPDATE screen_split_panel
      SET layout_config = $1, updated_at = NOW()
      WHERE id = $2 AND company_code = $3
      RETURNING *
    `;

    const result = await pool.query(query, [
      JSON.stringify(layoutConfig),
      id,
      companyCode,
    ]);

    if (result.rowCount === 0) {
      return res.status(404).json({
        success: false,
        message: "분할 패널 설정을 찾을 수 없습니다.",
      });
    }

    logger.info("분할 패널 설정 수정", { companyCode, id });

    return res.json({
      success: true,
      data: result.rows[0],
    });
  } catch (error: any) {
    logger.error("분할 패널 설정 수정 실패", error);
    return res.status(500).json({
      success: false,
      message: "분할 패널 설정 수정 중 오류가 발생했습니다.",
      error: error.message,
    });
  }
}

/**
 * 분할 패널 설정 삭제
 * DELETE /api/screen-split-panel/:id
 */
export async function deleteScreenSplitPanel(req: AuthenticatedRequest, res: Response) {
  const client = await pool.connect();

  try {
    const { id } = req.params;
    const companyCode = req.user!.companyCode;

    await client.query("BEGIN");

    // 1. 분할 패널 조회
    const selectQuery = `
      SELECT left_embedding_id, right_embedding_id, data_transfer_id
      FROM screen_split_panel
      WHERE id = $1 AND company_code = $2
    `;

    const selectResult = await client.query(selectQuery, [id, companyCode]);

    if (selectResult.rowCount === 0) {
      await client.query("ROLLBACK");
      return res.status(404).json({
        success: false,
        message: "분할 패널 설정을 찾을 수 없습니다.",
      });
    }

    const { left_embedding_id, right_embedding_id, data_transfer_id } =
      selectResult.rows[0];

    // 2. 분할 패널 삭제
    await client.query(
      "DELETE FROM screen_split_panel WHERE id = $1 AND company_code = $2",
      [id, companyCode]
    );

    // 3. 관련 임베딩 및 데이터 전달 설정 삭제 (CASCADE로 자동 삭제되지만 명시적으로)
    if (left_embedding_id) {
      await client.query(
        "DELETE FROM screen_embedding WHERE id = $1 AND company_code = $2",
        [left_embedding_id, companyCode]
      );
    }

    if (right_embedding_id) {
      await client.query(
        "DELETE FROM screen_embedding WHERE id = $1 AND company_code = $2",
        [right_embedding_id, companyCode]
      );
    }

    if (data_transfer_id) {
      await client.query(
        "DELETE FROM screen_data_transfer WHERE id = $1 AND company_code = $2",
        [data_transfer_id, companyCode]
      );
    }

    await client.query("COMMIT");

    logger.info("분할 패널 설정 삭제", { companyCode, id });

    return res.json({
      success: true,
      message: "분할 패널 설정이 삭제되었습니다.",
    });
  } catch (error: any) {
    await client.query("ROLLBACK");
    logger.error("분할 패널 설정 삭제 실패", error);
    return res.status(500).json({
      success: false,
      message: "분할 패널 설정 삭제 중 오류가 발생했습니다.",
      error: error.message,
    });
  } finally {
    client.release();
  }
}
