import { v4 as uuidv4 } from "uuid";
import { PostgreSQLService } from "../database/PostgreSQLService";
import {
  Dashboard,
  DashboardElement,
  CreateDashboardRequest,
  UpdateDashboardRequest,
  DashboardListQuery,
} from "../types/dashboard";

/**
 * 대시보드 서비스 - Raw Query 방식
 * PostgreSQL 직접 연결을 통한 CRUD 작업
 */
export class DashboardService {
  /**
   * 대시보드 생성
   */
  static async createDashboard(
    data: CreateDashboardRequest,
    userId: string,
    companyCode?: string
  ): Promise<Dashboard> {
    const dashboardId = uuidv4();
    const now = new Date();

    console.log("🔍 [createDashboard] 받은 데이터:", {
      title: data.title,
      settings: data.settings,
      settingsType: typeof data.settings,
      settingsStringified: JSON.stringify(data.settings || {}),
    });

    try {
      // 트랜잭션으로 대시보드와 요소들을 함께 생성
      const result = await PostgreSQLService.transaction(async (client) => {
        // 1. 대시보드 메인 정보 저장
        const settingsJson = JSON.stringify(data.settings || {});
        console.log("🔍 [createDashboard] DB INSERT settings:", settingsJson);

        await client.query(
          `
          INSERT INTO dashboards (
            id, title, description, is_public, created_by, 
            created_at, updated_at, tags, category, view_count, settings, company_code
          ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
        `,
          [
            dashboardId,
            data.title,
            data.description || null,
            data.isPublic || false,
            userId,
            now,
            now,
            JSON.stringify(data.tags || []),
            data.category || null,
            0,
            settingsJson,
            companyCode || "DEFAULT",
          ]
        );

        // 2. 대시보드 요소들 저장
        if (data.elements && data.elements.length > 0) {
          for (let i = 0; i < data.elements.length; i++) {
            const element = data.elements[i];
            const elementId = uuidv4(); // 항상 새로운 UUID 생성

            await client.query(
              `
              INSERT INTO dashboard_elements (
                id, dashboard_id, element_type, element_subtype,
                position_x, position_y, width, height,
                title, custom_title, show_header, content, data_source_config, chart_config,
                list_config, yard_config, custom_metric_config,
                display_order, created_at, updated_at
              ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)
            `,
              [
                elementId,
                dashboardId,
                element.type,
                element.subtype,
                element.position.x,
                element.position.y,
                element.size.width,
                element.size.height,
                element.title,
                element.customTitle || null,
                element.showHeader !== false, // 기본값 true
                element.content || null,
                JSON.stringify(element.dataSource || {}),
                JSON.stringify(element.chartConfig || {}),
                JSON.stringify(element.listConfig || null),
                JSON.stringify(element.yardConfig || null),
                JSON.stringify(element.customMetricConfig || null),
                i,
                now,
                now,
              ]
            );
          }
        }

        return dashboardId;
      });

      // 생성된 대시보드 반환
      try {
        const dashboard = await this.getDashboardById(dashboardId, userId);
        if (!dashboard) {
          console.error("대시보드 생성은 성공했으나 조회에 실패:", dashboardId);
          // 생성은 성공했으므로 기본 정보만이라도 반환
          return {
            id: dashboardId,
            title: data.title,
            description: data.description,
            thumbnailUrl: undefined,
            isPublic: data.isPublic || false,
            createdBy: userId,
            createdAt: now.toISOString(),
            updatedAt: now.toISOString(),
            tags: data.tags || [],
            category: data.category,
            viewCount: 0,
            elements: data.elements || [],
          };
        }

        return dashboard;
      } catch (fetchError) {
        console.error("생성된 대시보드 조회 중 오류:", fetchError);
        // 생성은 성공했으므로 기본 정보 반환
        return {
          id: dashboardId,
          title: data.title,
          description: data.description,
          thumbnailUrl: undefined,
          isPublic: data.isPublic || false,
          createdBy: userId,
          createdAt: now.toISOString(),
          updatedAt: now.toISOString(),
          tags: data.tags || [],
          category: data.category,
          viewCount: 0,
          elements: data.elements || [],
        };
      }
    } catch (error) {
      console.error("Dashboard creation error:", error);
      throw error;
    }
  }

  /**
   * 대시보드 목록 조회
   */
  static async getDashboards(
    query: DashboardListQuery,
    userId?: string,
    companyCode?: string
  ) {
    const {
      page = 1,
      limit = 20,
      search,
      category,
      isPublic,
      createdBy,
    } = query;

    const offset = (page - 1) * limit;

    try {
      // 기본 WHERE 조건
      let whereConditions = ["d.deleted_at IS NULL"];
      let params: any[] = [];
      let paramIndex = 1;

      // 회사 코드 필터링 - company_code가 일치하면 해당 회사 사용자는 모두 조회 가능
      if (companyCode) {
        if (companyCode === '*') {
          // 최고 관리자는 모든 대시보드 조회 가능
        } else {
          whereConditions.push(`d.company_code = $${paramIndex}`);
          params.push(companyCode);
          paramIndex++;
        }
      } else if (userId) {
        // 회사 코드 없이 userId만 있는 경우 (본인 생성 또는 공개)
        whereConditions.push(
          `(d.created_by = $${paramIndex} OR d.is_public = true)`
        );
        params.push(userId);
        paramIndex++;
      } else {
        // 비로그인 사용자는 공개 대시보드만
        whereConditions.push("d.is_public = true");
      }

      // 검색 조건
      if (search) {
        whereConditions.push(
          `(d.title ILIKE $${paramIndex} OR d.description ILIKE $${paramIndex + 1})`
        );
        params.push(`%${search}%`, `%${search}%`);
        paramIndex += 2;
      }

      // 카테고리 필터
      if (category) {
        whereConditions.push(`d.category = $${paramIndex}`);
        params.push(category);
        paramIndex++;
      }

      // 공개/비공개 필터
      if (typeof isPublic === "boolean") {
        whereConditions.push(`d.is_public = $${paramIndex}`);
        params.push(isPublic);
        paramIndex++;
      }

      // 작성자 필터
      if (createdBy) {
        whereConditions.push(`d.created_by = $${paramIndex}`);
        params.push(createdBy);
        paramIndex++;
      }

      const whereClause = whereConditions.join(" AND ");

      // 대시보드 목록 조회 (user_info 조인하여 생성자 이름 포함)
      const dashboardQuery = `
        SELECT 
          d.id,
          d.title,
          d.description,
          d.thumbnail_url,
          d.is_public,
          d.created_by,
          d.created_at,
          d.updated_at,
          d.tags,
          d.category,
          d.view_count,
          d.company_code,
          u.user_name as created_by_name,
          COUNT(de.id) as elements_count
        FROM dashboards d
        LEFT JOIN dashboard_elements de ON d.id = de.dashboard_id
        LEFT JOIN user_info u ON d.created_by = u.user_id
        WHERE ${whereClause}
        GROUP BY d.id, d.title, d.description, d.thumbnail_url, d.is_public, 
                 d.created_by, d.created_at, d.updated_at, d.tags, d.category, 
                 d.view_count, d.company_code, u.user_name
        ORDER BY d.updated_at DESC
        LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
      `;

      const dashboardResult = await PostgreSQLService.query(dashboardQuery, [
        ...params,
        limit,
        offset,
      ]);

      // 전체 개수 조회
      const countQuery = `
        SELECT COUNT(DISTINCT d.id) as total
        FROM dashboards d
        WHERE ${whereClause}
      `;

      const countResult = await PostgreSQLService.query(countQuery, params);
      const total = parseInt(countResult.rows[0]?.total || "0");

      return {
        dashboards: dashboardResult.rows.map((row: any) => ({
          id: row.id,
          title: row.title,
          description: row.description,
          thumbnailUrl: row.thumbnail_url,
          isPublic: row.is_public,
          createdBy: row.created_by,
          createdByName: row.created_by_name || row.created_by,
          createdAt: row.created_at,
          updatedAt: row.updated_at,
          tags: JSON.parse(row.tags || "[]"),
          category: row.category,
          viewCount: parseInt(row.view_count || "0"),
          elementsCount: parseInt(row.elements_count || "0"),
          companyCode: row.company_code,
        })),
        pagination: {
          page,
          limit,
          total,
          totalPages: Math.ceil(total / limit),
        },
      };
    } catch (error) {
      console.error("Dashboard list error:", error);
      throw error;
    }
  }

  /**
   * 대시보드 상세 조회
   * - company_code가 일치하면 해당 회사 사용자는 모두 조회 가능
   * - company_code가 '*'인 경우 최고 관리자만 조회 가능
   */
  static async getDashboardById(
    dashboardId: string,
    userId?: string,
    companyCode?: string
  ): Promise<Dashboard | null> {
    try {
      // 1. 대시보드 기본 정보 조회 (권한 체크 포함)
      let dashboardQuery: string;
      let dashboardParams: any[];

      if (companyCode) {
        // 회사 코드가 있으면 해당 회사 대시보드 또는 공개 대시보드 조회 가능
        // 최고 관리자(companyCode = '*')는 모든 대시보드 조회 가능
        if (companyCode === '*') {
          dashboardQuery = `
            SELECT d.*
            FROM dashboards d
            WHERE d.id = $1 AND d.deleted_at IS NULL
          `;
          dashboardParams = [dashboardId];
        } else {
          dashboardQuery = `
            SELECT d.*
            FROM dashboards d
            WHERE d.id = $1 AND d.deleted_at IS NULL
            AND d.company_code = $2
          `;
          dashboardParams = [dashboardId, companyCode];
        }
      } else if (userId) {
        // 회사 코드 없이 userId만 있는 경우 (본인 생성 또는 공개)
        dashboardQuery = `
          SELECT d.*
          FROM dashboards d
          WHERE d.id = $1 AND d.deleted_at IS NULL
          AND (d.created_by = $2 OR d.is_public = true)
        `;
        dashboardParams = [dashboardId, userId];
      } else {
        // 비로그인 사용자는 공개 대시보드만
        dashboardQuery = `
          SELECT d.*
          FROM dashboards d
          WHERE d.id = $1 AND d.deleted_at IS NULL
          AND d.is_public = true
        `;
        dashboardParams = [dashboardId];
      }

      const dashboardResult = await PostgreSQLService.query(
        dashboardQuery,
        dashboardParams
      );

      if (dashboardResult.rows.length === 0) {
        return null;
      }

      const dashboard = dashboardResult.rows[0];

      // 🔍 디버깅: settings 원본 확인
      console.log("🔍 [getDashboardById] dashboard.settings 원본:", {
        type: typeof dashboard.settings,
        value: dashboard.settings,
        raw: JSON.stringify(dashboard.settings),
      });

      // 2. 대시보드 요소들 조회
      const elementsQuery = `
        SELECT * FROM dashboard_elements
        WHERE dashboard_id = $1
        ORDER BY display_order ASC
      `;

      const elementsResult = await PostgreSQLService.query(elementsQuery, [
        dashboardId,
      ]);

      // 3. 요소 데이터 변환
      const elements: DashboardElement[] = elementsResult.rows.map(
        (row: any) => ({
          id: row.id,
          type: row.element_type,
          subtype: row.element_subtype,
          position: {
            x: row.position_x,
            y: row.position_y,
          },
          size: {
            width: row.width,
            height: row.height,
          },
          title: row.title,
          customTitle: row.custom_title || undefined,
          showHeader: row.show_header !== false, // 기본값 true
          content: row.content,
          dataSource: JSON.parse(row.data_source_config || "{}"),
          chartConfig: JSON.parse(row.chart_config || "{}"),
          listConfig: row.list_config
            ? typeof row.list_config === "string"
              ? JSON.parse(row.list_config)
              : row.list_config
            : undefined,
          yardConfig: row.yard_config
            ? typeof row.yard_config === "string"
              ? JSON.parse(row.yard_config)
              : row.yard_config
            : undefined,
          customMetricConfig: row.custom_metric_config
            ? typeof row.custom_metric_config === "string"
              ? JSON.parse(row.custom_metric_config)
              : row.custom_metric_config
            : undefined,
        })
      );

      // 🔍 디버깅: settings 파싱
      let parsedSettings = undefined;
      if (dashboard.settings) {
        if (typeof dashboard.settings === 'string') {
          parsedSettings = JSON.parse(dashboard.settings);
          console.log("🔍 [getDashboardById] settings 문자열 파싱:", parsedSettings);
        } else {
          parsedSettings = dashboard.settings;
          console.log("🔍 [getDashboardById] settings 이미 객체:", parsedSettings);
        }
      } else {
        console.log("🔍 [getDashboardById] settings 없음 (null/undefined)");
      }

      const result = {
        id: dashboard.id,
        title: dashboard.title,
        description: dashboard.description,
        thumbnailUrl: dashboard.thumbnail_url,
        isPublic: dashboard.is_public,
        createdBy: dashboard.created_by,
        createdAt: dashboard.created_at,
        updatedAt: dashboard.updated_at,
        tags: JSON.parse(dashboard.tags || "[]"),
        category: dashboard.category,
        viewCount: parseInt(dashboard.view_count || "0"),
        settings: parsedSettings,
        elements,
      };

      console.log("🔍 [getDashboardById] 최종 반환 settings:", result.settings);

      return result;
    } catch (error) {
      console.error("Dashboard get error:", error);
      throw error;
    }
  }

  /**
   * 대시보드 업데이트
   */
  static async updateDashboard(
    dashboardId: string,
    data: UpdateDashboardRequest,
    userId: string
  ): Promise<Dashboard | null> {
    try {
      const result = await PostgreSQLService.transaction(async (client) => {
        // 권한 체크
        const authCheckResult = await client.query(
          `
          SELECT id FROM dashboards 
          WHERE id = $1 AND created_by = $2 AND deleted_at IS NULL
        `,
          [dashboardId, userId]
        );

        if (authCheckResult.rows.length === 0) {
          throw new Error("대시보드를 찾을 수 없거나 수정 권한이 없습니다.");
        }

        const now = new Date();

        // 1. 대시보드 메인 정보 업데이트
        const updateFields: string[] = [];
        const updateParams: any[] = [];
        let paramIndex = 1;

        if (data.title !== undefined) {
          updateFields.push(`title = $${paramIndex}`);
          updateParams.push(data.title);
          paramIndex++;
        }
        if (data.description !== undefined) {
          updateFields.push(`description = $${paramIndex}`);
          updateParams.push(data.description);
          paramIndex++;
        }
        if (data.isPublic !== undefined) {
          updateFields.push(`is_public = $${paramIndex}`);
          updateParams.push(data.isPublic);
          paramIndex++;
        }
        if (data.tags !== undefined) {
          updateFields.push(`tags = $${paramIndex}`);
          updateParams.push(JSON.stringify(data.tags));
          paramIndex++;
        }
        if (data.category !== undefined) {
          updateFields.push(`category = $${paramIndex}`);
          updateParams.push(data.category);
          paramIndex++;
        }
        if (data.settings !== undefined) {
          const settingsJson = JSON.stringify(data.settings);
          console.log("🔍 [updateDashboard] DB UPDATE settings:", {
            original: data.settings,
            stringified: settingsJson,
          });
          updateFields.push(`settings = $${paramIndex}`);
          updateParams.push(settingsJson);
          paramIndex++;
        }

        updateFields.push(`updated_at = $${paramIndex}`);
        updateParams.push(now);
        paramIndex++;

        updateParams.push(dashboardId);

        if (updateFields.length > 1) {
          // updated_at 외에 다른 필드가 있는 경우
          const updateQuery = `
            UPDATE dashboards 
            SET ${updateFields.join(", ")}
            WHERE id = $${paramIndex}
          `;

          await client.query(updateQuery, updateParams);
        }

        // 2. 요소 업데이트 (있는 경우)
        if (data.elements) {
          // 기존 요소들 삭제
          await client.query(
            `
            DELETE FROM dashboard_elements WHERE dashboard_id = $1
          `,
            [dashboardId]
          );

          // 새 요소들 추가
          for (let i = 0; i < data.elements.length; i++) {
            const element = data.elements[i];
            const elementId = uuidv4();

            await client.query(
              `
              INSERT INTO dashboard_elements (
                id, dashboard_id, element_type, element_subtype,
                position_x, position_y, width, height,
                title, custom_title, show_header, content, data_source_config, chart_config,
                list_config, yard_config, custom_metric_config,
                display_order, created_at, updated_at
              ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)
            `,
              [
                elementId,
                dashboardId,
                element.type,
                element.subtype,
                element.position.x,
                element.position.y,
                element.size.width,
                element.size.height,
                element.title,
                element.customTitle || null,
                element.showHeader !== false, // 기본값 true
                element.content || null,
                JSON.stringify(element.dataSource || {}),
                JSON.stringify(element.chartConfig || {}),
                JSON.stringify(element.listConfig || null),
                JSON.stringify(element.yardConfig || null),
                JSON.stringify(element.customMetricConfig || null),
                i,
                now,
                now,
              ]
            );
          }
        }

        return dashboardId;
      });

      // 업데이트된 대시보드 반환
      return await this.getDashboardById(dashboardId, userId);
    } catch (error) {
      console.error("Dashboard update error:", error);
      throw error;
    }
  }

  /**
   * 대시보드 삭제 (소프트 삭제)
   */
  static async deleteDashboard(
    dashboardId: string,
    userId: string
  ): Promise<boolean> {
    try {
      const now = new Date();

      const result = await PostgreSQLService.query(
        `
        UPDATE dashboards 
        SET deleted_at = $1, updated_at = $2
        WHERE id = $3 AND created_by = $4 AND deleted_at IS NULL
      `,
        [now, now, dashboardId, userId]
      );

      return (result.rowCount || 0) > 0;
    } catch (error) {
      console.error("Dashboard delete error:", error);
      throw error;
    }
  }

  /**
   * 조회수 증가
   */
  static async incrementViewCount(dashboardId: string): Promise<void> {
    try {
      await PostgreSQLService.query(
        `
        UPDATE dashboards 
        SET view_count = view_count + 1 
        WHERE id = $1 AND deleted_at IS NULL
      `,
        [dashboardId]
      );
    } catch (error) {
      console.error("View count increment error:", error);
      // 조회수 증가 실패는 치명적이지 않으므로 에러를 던지지 않음
    }
  }

  /**
   * 사용자 권한 체크
   */
  static async checkUserPermission(
    dashboardId: string,
    userId: string,
    requiredPermission: "view" | "edit" | "admin" = "view"
  ): Promise<boolean> {
    try {
      const result = await PostgreSQLService.query(
        `
        SELECT 
          CASE 
            WHEN d.created_by = $2 THEN 'admin'
            WHEN d.is_public = true THEN 'view'
            ELSE 'none'
          END as permission
        FROM dashboards d
        WHERE d.id = $1 AND d.deleted_at IS NULL
      `,
        [dashboardId, userId]
      );

      if (result.rows.length === 0) {
        return false;
      }

      const userPermission = result.rows[0].permission;

      // 권한 레벨 체크
      const permissionLevels = { view: 1, edit: 2, admin: 3 };
      const userLevel =
        permissionLevels[userPermission as keyof typeof permissionLevels] || 0;
      const requiredLevel = permissionLevels[requiredPermission];

      return userLevel >= requiredLevel;
    } catch (error) {
      console.error("Permission check error:", error);
      return false;
    }
  }
}
