/**
 * 중앙화된 API 서비스
 * 모든 외부 API 요청을 이 모듈에서 관리
 */

interface ApiResponse<T = any> {
    data: T;
    status: number;
    message?: string;
}

interface RequestConfig {
    method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
    headers?: Record<string, string>;
    body?: any;
    timeout?: number;
    params?: Record<string, string | number | undefined>;
}

class ApiService {
    private baseURL: string;
    private defaultTimeout: number = 30000; // 30초

    constructor(baseURL: string) {
        this.baseURL = baseURL;
    }

    /**
     * 토큰을 가져오는 헬퍼 함수
     */
    private getToken(): string | null {
        if (typeof window === 'undefined') return null;

        // localStorage에서 토큰 우선 확인
        const localToken = localStorage.getItem('token');
        if (localToken) return localToken;

        // 쿠키에서 토큰 확인
        const cookieToken = document.cookie
            .split('; ')
            .find(row => row.startsWith('token='))
            ?.split('=')[1];

        return cookieToken || null;
    }

    /**
     * 토큰 삭제 및 토큰 만료 모달 표시
     */
    private handleTokenError() {
        if (typeof window === 'undefined') return;

        // 토큰 삭제
        localStorage.removeItem('token');
        document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';

        // 로그인 페이지가 아닐 때만 모달 표시
        const currentPath = window.location.pathname;
        if (currentPath !== '/login') {
            // 전역 이벤트 발생하여 모달 표시
            window.dispatchEvent(new CustomEvent('tokenExpired'));
        }
    }

    /**
     * 기본 헤더 생성
     */
    private getDefaultHeaders(isFormData: boolean = false): Record<string, string> {
        const headers: Record<string, string> = {};

        // FormData인 경우 Content-Type을 설정하지 않음 (브라우저가 자동으로 설정)
        if (!isFormData) {
            headers['Content-Type'] = 'application/json';
        }

        const token = this.getToken();
        if (token) {
            headers['Authorization'] = `Bearer ${token}`;
        }

        return headers;
    }

    /**
     * 타임아웃이 있는 fetch
     */
    private async fetchWithTimeout(url: string, options: RequestInit, timeout: number): Promise<Response> {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), timeout);

        try {
            const response = await fetch(url, {
                ...options,
                signal: controller.signal,
            });
            clearTimeout(timeoutId);
            return response;
        } catch (error) {
            clearTimeout(timeoutId);
            if (error instanceof Error && error.name === 'AbortError') {
                throw new Error('요청 시간이 초과되었습니다.');
            }
            throw error;
        }
    }

    /**
     * 공통 API 요청 함수
     */
    private async request<T = any>(
        endpoint: string,
        config: RequestConfig = {}
    ): Promise<ApiResponse<T>> {
        const {
            method = 'GET',
            headers = {},
            body,
            timeout = this.defaultTimeout,
            params
        } = config;

        let url = endpoint.startsWith('http') ? endpoint : `${this.baseURL}${endpoint}`;
        
        // 쿼리 파라미터 추가
        if (params) {
            const queryParams = new URLSearchParams();
            Object.entries(params).forEach(([key, value]) => {
                if (value !== undefined && value !== null) {
                    queryParams.append(key, String(value));
                }
            });
            const queryString = queryParams.toString();
            if (queryString) {
                url += (url.includes('?') ? '&' : '?') + queryString;
            }
        }

        // FormData 여부 확인
        const isFormData = body instanceof FormData;

        const requestOptions: RequestInit = {
            method,
            headers: {
                ...this.getDefaultHeaders(isFormData),
                ...headers,
            },
        };

        if (body && method !== 'GET') {
            // FormData인 경우 그대로 사용, 아닌 경우 JSON으로 변환
            requestOptions.body = isFormData ? body : JSON.stringify(body);
        }

        try {
            const response = await this.fetchWithTimeout(url, requestOptions, timeout);

            if (!response.ok) {
                // 토큰 오류 (401, 403) 발생 시 처리
                if (response.status === 401 || response.status === 403) {
                    this.handleTokenError();
                    throw new Error('인증이 만료되었습니다. 다시 로그인해주세요.');
                }

                let errorMessage = `HTTP ${response.status}: ${response.statusText}`;

                try {
                    const errorData = await response.json();
                    if (errorData.message) {
                        errorMessage = errorData.message;
                    } else if (errorData.error) {
                        errorMessage = errorData.error;
                    }
                } catch (parseError) {
                    // JSON 파싱 실패 시 기본 에러 메시지 사용
                }

                throw new Error(errorMessage);
            }

            const data = await response.json();

            return {
                data,
                status: response.status,
            };
        } catch (error) {
            if (error instanceof Error) {
                throw error;
            }
            throw new Error('알 수 없는 오류가 발생했습니다.');
        }
    }

    // ===== 인증 관련 API =====

    /**
     * 로그인
     */
    async login(email: string, password: string) {
        return this.request('/auth/login', {
            method: 'POST',
            body: { email, password },
        });
    }

    /**
     * 사용자 정보 조회
     */
    async getCurrentUser() {
        return this.request('/auth/me');
    }

    /**
     * 회원가입
     */
    async register(userData: {
        email: string;
        emailCode: string;
        password: string;
        passwordConfirm: string;
        name: string;
        phone: string;
        gender: 'MALE' | 'FEMALE';
        birthDate: string;
    }) {
        return this.request('/auth/signup', {
            method: 'POST',
            body: userData,
        });
    }

    /**
     * 이메일 인증번호 전송
     */
    async sendEmailVerification(email: string) {
        return this.request('/auth/verify-email/send', {
            method: 'POST',
            body: { email },
        });
    }

    /**
     * 이메일 인증번호 확인
     */
    async verifyEmailCode(email: string, emailCode: string) {
        return this.request('/auth/verify-email/confirm', {
            method: 'POST',
            body: { email, emailCode },
        });
    }

    /**
     * 아이디 찾기
     */
    async findUserId(name: string, phone: string) {
        return this.request('/auth/find-id', {
            method: 'POST',
            body: { name, phone },
        });
    }

    /**
     * 비밀번호 재설정 이메일 전송
     */
    async sendPasswordReset(email: string) {
        return this.request('/auth/password/forgot', {
            method: 'POST',
            body: { email },
        });
    }

    /**
     * 비밀번호 재설정 코드 확인
     */
    async verifyPasswordResetCode(email: string, code: string) {
        return this.request('/auth/password/confirm', {
            method: 'POST',
            body: { email, emailCode: code },
        });
    }

    /**
     * 비밀번호 재설정
     */
    async resetPassword(email: string, emailCode: string, newPassword: string, newPasswordConfirm: string) {
        return this.request('/auth/password/reset', {
            method: 'POST',
            body: { email, emailCode, newPassword, newPasswordConfirm },
        });
    }

    /**
     * 계정 삭제
     */
    async deleteAccount() {
        return this.request('/auth/delete/me', {
            method: 'DELETE',
        });
    }

    // ===== 관리자 관련 API =====

    /**
     * 과목 리스트 조회
     */
    async getSubjects() {
        return this.request('/subjects');
    }

    /**
     * 과목 생성
     */
    async createSubject(subjectData: {
        title: string;
        instructor: string;
        imageKey?: string;
    }) {
        return this.request('/subjects', {
            method: 'POST',
            body: subjectData,
        });
    }

    /**
     * 과목 수정
     */
    async updateSubject(subjectId: string, subjectData: {
        title: string;
        instructor: string;
        imageKey?: string | null;
    }) {
        return this.request(`/subjects/${subjectId}`, {
            method: 'PATCH',
            body: subjectData,
        });
    }

    /**
     * 과목 삭제
     */
    async deleteSubject(subjectId: string) {
        return this.request(`/subjects/${subjectId}`, {
            method: 'DELETE',
        });
    }

    /**
     * 사용자 리스트 조회
     */
    async getUsers() {
        return this.request('/users');
    }

    /**
     * 사용자 생성
     */
    async createUser(userData: any) {
        return this.request('/users', {
            method: 'POST',
            body: userData,
        });
    }

    /**
     * 사용자 수정
     */
    async updateUser(userId: string, userData: any) {
        return this.request(`/users/${userId}`, {
            method: 'PUT',
            body: userData,
        });
    }

    /**
     * 사용자 삭제
     */
    async deleteUser(userId: string) {
        return this.request(`/users/${userId}`, {
            method: 'DELETE',
        });
    }

    /**
     * 회원 리스트 조회 (컴팩트) - 관리자 전용
     */
    async getUsersCompact(params?: { type?: string; limit?: number }) {
        return this.request('/admin/users/compact', {
            params: params ? {
                ...(params.type && { type: params.type }),
                ...(params.limit && { limit: params.limit }),
            } : undefined,
        });
    }

    /**
     * 단일 회원 정지 (ID 기준) - 관리자 전용
     */
    async suspendUser(userId: string | number) {
        return this.request(`/admin/users/${userId}/suspend`, {
            method: 'PATCH',
        });
    }

    /**
     * 단일 회원 정지 해제 (ID 기준) - 관리자 전용
     */
    async unsuspendUser(userId: string | number) {
        return this.request(`/admin/users/${userId}/unsuspend`, {
            method: 'PATCH',
        });
    }
    /**
     * 대량 정지 (ID 배열) - 관리자 전용
     */
    async suspendUsers(userIds: (string | number)[]) {
        return this.request('/admin/users/suspend', {
            method: 'POST',
            body: { userIds },
        });
    }

    // ===== 기타 API =====

    /**
     * 공지사항 목록 조회 (페이징)
     */
    async getNotices() {
        return this.request('/notices');
    }

    /**
     * 공지 단건 조회
     */
    async getNotice(id: string | number) {
        return this.request(`/notices/${id}`);
    }

    /**
     * 공지 등록 (ADMIN)
     */
    async createNotice(noticeData: any) {
        return this.request('/notices', {
            method: 'POST',
            body: noticeData,
        });
    }

    /**
     * 공지 수정 (ADMIN)
     */
    async updateNotice(id: string | number, noticeData: any) {
        return this.request(`/notices/${id}`, {
            method: 'PATCH',
            body: noticeData,
        });
    }

    /**
     * 공지 삭제 (ADMIN)
     */
    async deleteNotice(id: string | number) {
        return this.request(`/notices/${id}`, {
            method: 'DELETE',
        });
    }

    /**
     * 강좌 조회
     */
    async getLessons() {
        return this.request('/lessons');
    }

    /**
     * 강좌 리스트 조회
     */
    async getLectures() {
        return this.request('/lectures', {
            method: 'GET',
        });
    }

    /**
     * 특정 강좌 조회
     */
    async getLecture(id: string | number) {
        return this.request(`/lectures/${id}`, {
            method: 'GET',
        });
    }

    /**
     * 강좌(lecture) 생성
     */
    async createLecture(lectureData: {
        subjectId: number;
        title: string;
        objective: string;
        videoUrl?: string | string[];
        webglUrl?: string | string[];
        csvKey?: string;
    }) {
        return this.request('/lectures', {
            method: 'POST',
            body: lectureData,
        });
    }

    /**
     * 강좌(lecture) 수정
     */
    async updateLecture(lectureId: string | number, lectureData: {
        subjectId?: number;
        title?: string;
        objective?: string;
        videoUrl?: string | string[];
        webglUrl?: string | string[];
        csvKey?: string;
        csvUrl?: string;
    }) {
        return this.request(`/lectures/${lectureId}`, {
            method: 'PATCH',
            body: lectureData,
        });
    }

    /**
     * 강좌(lecture) 삭제
     */
    async deleteLecture(lectureId: string | number) {
        return this.request(`/lectures/${lectureId}`, {
            method: 'DELETE',
        });
    }

    /**
     * 리소스 조회
     */
    async getResources() {
        return this.request('/resources');
    }

    // ===== 학습 자료실 (Library) 관련 API =====

    /**
     * 학습 자료실 목록 조회 (로그인 필요, 페이징)
     */
    async getLibrary() {
        return this.request('/library');
    }

    /**
     * 학습 자료 단건 조회
     */
    async getLibraryItem(id: string | number) {
        return this.request(`/library/${id}`);
    }

    /**
     * 학습 자료 등록 (ADMIN)
     */
    async createLibraryItem(libraryData: any) {
        return this.request('/library', {
            method: 'POST',
            body: libraryData,
        });
    }

    /**
     * 학습 자료 수정 (ADMIN)
     */
    async updateLibraryItem(id: string | number, libraryData: any) {
        return this.request(`/library/${id}`, {
            method: 'PATCH',
            body: libraryData,
        });
    }

    /**
     * 학습 자료 삭제 (ADMIN)
     */
    async deleteLibraryItem(id: string | number) {
        return this.request(`/library/${id}`, {
            method: 'DELETE',
        });
    }

    // ===== 진행률 (Progress) 관련 API =====

    /**
     * 특정 강의에서 "내" 진행률 조회
     */
    async getLectureProgress(lectureId: string | number) {
        return this.request(`/progress/lectures/${lectureId}`);
    }

    /**
     * 강의 진행(Heartbeat) 업서트
     */
    async updateLectureProgress(progressData: any) {
        return this.request('/progress/lectures/progress', {
            method: 'POST',
            body: progressData,
        });
    }

    /**
     * 과목 진행률 요약(내 기준)
     */
    async getSubjectProgressSummary(subjectId: string | number) {
        return this.request(`/progress/subjects/${subjectId}/summary`);
    }

    // ===== 평가 (Evaluation) 관련 API =====

    /**
     * 강의 평가 제출 (60점 이상만 저장)
     */
    async submitEvaluation(evaluationData: any) {
        return this.request('/evaluations', {
            method: 'POST',
            body: evaluationData,
        });
    }

    /**
     * 특정 강의에서 "내" 마지막 평가 결과 조회
     */
    async getMyEvaluation(lectureId: string | number) {
        return this.request(`/evaluations/lectures/${lectureId}/me`);
    }

    /**
     * 특정 강의에서 특정 수강생의 마지막 평가 결과 조회 (ADMIN/INSTRUCTOR)
     */
    async getUserEvaluation(lectureId: string | number, userId: string | number) {
        return this.request(`/evaluations/lectures/${lectureId}/users/${userId}`);
    }

    // ===== 관리자 강의 현황 관련 API =====

    /**
     * 강좌별 학습/문제 제출/수료 현황 리스트 (관리자/강사용)
     */
    async getLecturesStatus() {
        return this.request('/admin/lectures/status');
    }

    /**
     * 특정 강좌 + 특정 학습자의 수강/문제 풀이 상세 (관리자/강사용)
     */
    async getLectureStudentDetail(lectureId: string | number, userId: string | number) {
        return this.request(`/admin/lectures/${lectureId}/students/${userId}/detail`);
    }

    // ===== 수료증 및 결과 관련 API =====

    /**
     * 특정 과목 수료증용 정보 조회 (학생 본인)
     */
    async getCertificate(subjectId: string | number) {
        return this.request(`/certificates/subjects/${subjectId}`);
    }

    /**
     * 학생 기준 학습 결과(수료 과목 목록)
     */
    async getMyResults() {
        return this.request('/results/my-subjects');
    }

    // ===== 파일 업로드 관련 API =====

    /**
     * 단일 파일 업로드
     * @param file 업로드할 파일 (File 객체 또는 Blob)
     */
    async uploadFile(file: File | Blob) {
        const formData = new FormData();
        formData.append('file', file);

        return this.request('/uploads-api/file', {
            method: 'POST',
            body: formData,
        });
    }

    /**
     * 다중 파일 업로드
     * @param files 업로드할 파일 배열 (File[] 또는 Blob[])
     */
    async uploadFiles(files: (File | Blob)[]) {
        const formData = new FormData();
        files.forEach((file, index) => {
            formData.append('files', file);
        });

        return this.request('/uploads-api/files', {
            method: 'POST',
            body: formData,
        });
    }

    /**
     * 파일 다운로드
     * @param fileKey 파일 키
     * @returns 파일 URL (Blob URL), 파일이 없으면 null 반환
     */
    async getFile(fileKey: string): Promise<string | null> {
        const url = `${this.baseURL}/api/files/${fileKey}`;
        const token = this.getToken();

        const response = await fetch(url, {
            method: 'GET',
            headers: {
                ...(token && { Authorization: `Bearer ${token}` }),
            },
        });

        // 404 에러는 이미지가 없는 것으로 간주하고 null 반환
        if (response.status === 404) {
            return null;
        }

        if (!response.ok) {
            throw new Error(`파일을 가져오는데 실패했습니다. (${response.status})`);
        }

        // 이미지 파일이므로 Blob으로 변환하여 URL 생성
        const blob = await response.blob();
        return URL.createObjectURL(blob);
    }
}

// 기본 API 서비스 인스턴스 생성
const apiService = new ApiService(
    process.env.NEXT_PUBLIC_API_BASE_URL || 'https://hrdi.coconutmeet.net'
);

export default apiService;
export type { ApiResponse, RequestConfig };
