// ====================================================================
// employee_service.pc
// - DB 접속/해제 및 CRUD (Create, Read, Update, Delete) 로직 구현
// ====================================================================

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// employee.h는 구조체 선언이 빠졌으므로, 함수 원형만 가져옵니다.
#include "employee.h" 

// 1. 🚨🚨 Pro*C 필수 영역: SQLCA 및 호스트 변수 선언 🚨🚨
EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;
// DB 접속 정보 (사용자 환경에 맞게 수정 필요)
char db_user[] = "scott"; 
char db_pass[] = "tiger";
char db_connect_string[] = "ORCL"; // TNS 이름 또는 SID

// ⚠️ PCC-S-02201 오류 해결: EMPLOYEE_T 정의를 여기에 직접 포함 ⚠️
struct EMPLOYEE_T {
    char emp_id[6];     
    char full_name[31]; 
    char hire_date[9];  
    char married[2];    
    long long salary;       
    char gender[2];     
};
typedef struct EMPLOYEE_T EMPLOYEE_T;
// -----------------------------------------------------------
EXEC SQL END DECLARE SECTION;

// ====================================================================
// Connection Logic
// ====================================================================

// DB 연결
void connect_db() {
    printf("DB 연결 시도 중...\\n");
    // [사용자 이름/패스워드]@[연결 문자열] 형식으로 연결
    EXEC SQL CONNECT :db_user IDENTIFIED BY :db_pass USING :db_connect_string;

    if (sqlca.sqlcode != 0) {
        printf(" [DB ERROR] 연결 실패 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        exit(1);
    }
    printf("✅ DB에 성공적으로 연결되었습니다.\\n");
}

// DB 연결 해제
void disconnect_db() {
    EXEC SQL COMMIT RELEASE; // 모든 트랜잭션 커밋 및 연결 해제
    printf("DB 연결이 해제되었습니다.\\n");
}

// ====================================================================
// A. READ (조회)
// ====================================================================

// 1. 전체 목록 조회 (READ All)
EMPLOYEE_T* select_all_employees(int* count) {
    // DB 로직에서 사용할 변수 선언
    EXEC SQL BEGIN DECLARE SECTION;
    EMPLOYEE_T current_emp;
    EXEC SQL END DECLARE SECTION;

    // 조회 결과를 담을 동적 배열 포인터
    EMPLOYEE_T* employees = NULL;
    int found_count = 0;
    
    // 커서 선언 (전체 조회)
    EXEC SQL DECLARE emp_cursor CURSOR FOR
        SELECT EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY 
        FROM EMPLOYEES
        ORDER BY EMPL_ID;

    EXEC SQL OPEN emp_cursor;

    // 데이터 Fetch 및 동적 배열에 추가
    while (1) {
        EXEC SQL FETCH emp_cursor INTO
            :current_emp.emp_id, :current_emp.full_name, :current_emp.hire_date,
            :current_emp.married, :current_emp.gender, :current_emp.salary;

        if (sqlca.sqlcode == 1403) break; // NO DATA FOUND
        if (sqlca.sqlcode != 0) {
            printf(" [DB ERROR] 전체 조회 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
            EXEC SQL CLOSE emp_cursor;
            *count = 0;
            if (employees != NULL) free(employees);
            return NULL;
        }

        // 동적 메모리 재할당 (새로운 레코드를 위한 공간 확보)
        employees = (EMPLOYEE_T*)realloc(employees, (found_count + 1) * sizeof(EMPLOYEE_T));
        if (employees == NULL) {
            printf(" [MEMORY ERROR] 메모리 할당 실패\\n");
            EXEC SQL CLOSE emp_cursor;
            *count = 0;
            return NULL;
        }

        // 현재 조회된 데이터를 동적 배열의 마지막 위치에 복사
        employees[found_count] = current_emp; 
        found_count++;
    }
    EXEC SQL CLOSE emp_cursor;
    
    *count = found_count;
    return employees; // 조회된 직원 정보 배열 포인터 반환
}

// 2. 상세 목록 조회 (READ One)
int select_employee_by_id(const char* emp_id, EMPLOYEE_T* result_emp) {
    EXEC SQL BEGIN DECLARE SECTION; 
    char l_search_id[6];
    EXEC SQL END DECLARE SECTION;

    // 입력받은 사번을 Host Variable에 복사
    strcpy(l_search_id, emp_id);
    
    EXEC SQL SELECT EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY 
        INTO :result_emp->emp_id, :result_emp->full_name, :result_emp->hire_date, 
             :result_emp->married, :result_emp->gender, :result_emp->salary
        FROM EMPLOYEES
        WHERE EMPL_ID = :l_search_id;

    if (sqlca.sqlcode == 1403) {
        return -1; // 데이터 없음 (NO DATA FOUND)
    } else if (sqlca.sqlcode != 0) {
        printf(" [DB ERROR] 상세 조회 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -2; // DB 오류
    }

    return 0; // 성공
}

// ====================================================================
// B. CREATE, UPDATE, DELETE (추가, 수정, 삭제)
// ====================================================================

// 3. 직원 정보 추가 (CREATE)
int insert_employee(const EMPLOYEE_T* new_emp) {
    EXEC SQL BEGIN DECLARE SECTION;
    EMPLOYEE_T l_emp;
    EXEC SQL END DECLARE SECTION;

    // 구조체 복사
    l_emp = *new_emp;
    
    EXEC SQL INSERT INTO EMPLOYEES (EMPL_ID, FULL_NAME, HIRE_DATE, MARRIED, GENDER, SALARY)
        VALUES (:l_emp.emp_id, :l_emp.full_name, :l_emp.hire_date, :l_emp.married, :l_emp.gender, :l_emp.salary);

    if (sqlca.sqlcode != 0) {
        printf(" [DB ERROR] 직원 추가 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1; // DB 오류
    }

    EXEC SQL COMMIT; // 변경 사항 반영
    return 0; // 성공
}

// 4. 직원 정보 수정 (UPDATE)
int update_employee(const EMPLOYEE_T* updated_emp) {
    EXEC SQL BEGIN DECLARE SECTION;
    EMPLOYEE_T l_emp;
    EXEC SQL END DECLARE SECTION;

    l_emp = *updated_emp;
    
    EXEC SQL UPDATE EMPLOYEES
        SET FULL_NAME = :l_emp.full_name, 
            HIRE_DATE = :l_emp.hire_date, 
            MARRIED = :l_emp.married, 
            GENDER = :l_emp.gender, 
            SALARY = :l_emp.salary
        WHERE EMPL_ID = :l_emp.emp_id;

    if (sqlca.sqlcode != 0 && sqlca.sqlcode != 100) {
        printf(" [DB ERROR] 직원 수정 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1; // DB 오류
    }

    if (sqlca.sqlcode == 100 || sqlca.sqlcode == 1403) { // 100은 UPDATE/DELETE 시 레코드가 없을 때 주로 발생
        return 100; // 수정된 데이터 없음 (사번 없음)
    }

    EXEC SQL COMMIT; // 변경 사항 반영
    return 0; // 성공
}

// 5. 직원 정보 삭제 (DELETE)
int delete_employee(const char* emp_id) {
    EXEC SQL BEGIN DECLARE SECTION;
    char l_del_id[6];
    EXEC SQL END DECLARE SECTION;

    strcpy(l_del_id, emp_id);
    
    EXEC SQL DELETE FROM EMPLOYEES
        WHERE EMPL_ID = :l_del_id;

    if (sqlca.sqlcode != 0 && sqlca.sqlcode != 100) {
        printf(" [DB ERROR] 직원 삭제 오류 (SQLCODE: %d): %s\\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1; // DB 오류
    }

    if (sqlca.sqlcode == 100 || sqlca.sqlcode == 1403) {
        return 100; // 삭제된 데이터 없음 (사번 없음)
    }

    EXEC SQL COMMIT; // 변경 사항 반영
    return 0; // 성공
}