import os
import tempfile
import gradio as gr

import numpy as np  # (필요하다면)
import imageio
from PIL import Image

import moviepy.editor as me  # MoviePy 전체 임포트

LOGS = []

def log_step(message: str):
    LOGS.append(message)
    print(message)
    return "\n".join(LOGS)

def parse_time_str(time_str: str):
    try:
        parts = time_str.strip().split(":")
        if len(parts) == 3:
            h, m, s = parts
            return int(h)*3600 + int(m)*60 + float(s)
        elif len(parts) == 2:
            m, s = parts
            return int(m)*60 + float(s)
        elif len(parts) == 1:
            return float(parts[0])
        else:
            return 0.0
    except:
        return 0.0

def upload_video(video_file):
    if video_file is None:
        return None, "업로드된 파일이 없습니다.", None, log_step("[단계 1] 업로드된 파일이 없습니다.")
    temp_dir = tempfile.mkdtemp()
    temp_video_path = os.path.join(temp_dir, video_file.name)
    with open(temp_video_path, "wb") as f:
        f.write(video_file.read())
    try:
        clip = me.VideoFileClip(temp_video_path)
        duration_sec = clip.duration
        msg = f"재생 시간: {duration_sec:.2f}초"
        log_out = log_step("[단계 1] 비디오 업로드 및 재생 확인 완료")
        return temp_video_path, msg, duration_sec, log_out
    except Exception as e:
        err_log = log_step(f"[단계 1] 업로드 에러: {e}")
        return None, f"영상 처리 에러: {e}", None, err_log

def generate_thumbnails(video_path, start_time_str, end_time_str, log_history):
    log_step("[단계 4] 시작/끝 시간 입력 완료")
    start_s = parse_time_str(start_time_str)
    end_s   = parse_time_str(end_time_str)

    if not video_path:
        return None, None, log_step("[단계 5] 비디오 미업로드 → 썸네일 불가")
    
    try:
        clip = me.VideoFileClip(video_path)
        duration = clip.duration
        if start_s < 0: start_s = 0
        if end_s > duration: end_s = duration
        if start_s > end_s: start_s, end_s = end_s, start_s

        thumb1 = clip.get_frame(start_s)
        thumb2 = clip.get_frame(end_s)

        thumb1_img = Image.fromarray(thumb1)
        thumb2_img = Image.fromarray(thumb2)

        log_out = log_step("[단계 5] 썸네일 생성 완료")
        return thumb1_img, thumb2_img, log_out
    except Exception as e:
        err_log = log_step(f"[단계 5] 썸네일 생성 에러: {e}")
        return None, None, err_log

def create_gif(video_path, start_time_str, end_time_str, resolution, fps, speed, loop_count, log_history):
    if not video_path:
        return None, None, log_step("[단계 10] GIF 생성 실패: 비디오가 업로드되지 않음.")
    
    start_s = parse_time_str(start_time_str)
    end_s   = parse_time_str(end_time_str)

    try:
        clip = me.VideoFileClip(video_path)
        duration = clip.duration
        if start_s < 0: start_s = 0
        if end_s > duration: end_s = duration
        if start_s > end_s: start_s, end_s = end_s, start_s

        subclip = clip.subclip(start_s, end_s)
        if speed != 1.0:
            subclip = subclip.fx(me.vfx.speedx, speed)

        # 해상도 조절(기본 100%)
        w, h = subclip.size
        if resolution < 100:
            scale = resolution / 100.0
            subclip = subclip.resize((int(w * scale), int(h * scale)))

        # FPS
        fps = int(fps) if fps > 0 else None

        # 반복 횟수
        loop = loop_count  # 0=무한

        temp_dir = tempfile.mkdtemp()
        gif_path = os.path.join(temp_dir, "output.gif")

        subclip.write_gif(gif_path, fps=fps, loop=loop)

        log_out1 = log_step("[단계 10] 'GIF 생성' 버튼 클릭됨")
        log_out2 = log_step("[단계 11] GIF 미리보기 생성 완료")
        log_out3 = log_step("[단계 12] GIF 다운로드 준비 완료")

        preview_img = Image.open(gif_path)
        return preview_img, gif_path, "\n".join([log_out1, log_out2, log_out3])
    except Exception as e:
        err_log = log_step(f"[단계 10~12] GIF 생성 에러: {e}")
        return None, None, err_log

def build_interface():
    with gr.Blocks() as demo:
        gr.Markdown("## 동영상을 GIF로 변환하기")

        video_upload = gr.File(label="비디오 업로드", file_types=["video"])
        video_player = gr.Video(label="업로드된 영상 미리보기")
        video_info   = gr.Textbox(label="업로드된 영상 정보", interactive=False)

        video_path_state = gr.State()
        video_duration_state = gr.State()

        log_box = gr.Textbox(label="로그", interactive=False, lines=10)

        with gr.Row():
            start_time = gr.Textbox(label="시작 시간 (HH:MM:SS/ MM:SS)", value="0:00")
            end_time   = gr.Textbox(label="끝 시간 (HH:MM:SS/ MM:SS)", value="0:10")

        with gr.Row():
            thumb1 = gr.Image(label="시작 지점 썸네일")
            thumb2 = gr.Image(label="끝 지점 썸네일")

        resolution_slider = gr.Slider(1, 100, 100, step=1, label="해상도(%)")
        fps_slider        = gr.Slider(1, 60, 30, step=1, label="FPS")
        speed_slider      = gr.Slider(0.1, 3.0, 1.0, step=0.1, label="재생 속도(배)")
        loop_slider       = gr.Slider(0, 10, 0, step=1, label="GIF 반복 횟수 (0=무한)")

        generate_gif_btn  = gr.Button("GIF 생성")

        gif_preview  = gr.Image(label="GIF 미리보기")
        gif_download = gr.File(label="GIF 다운로드(클릭하여 저장)")

        # 이벤트 바인딩
        video_upload.change(
            fn=upload_video,
            inputs=video_upload,
            outputs=[video_path_state, video_info, video_duration_state, log_box]
        )
        start_time.change(
            fn=generate_thumbnails,
            inputs=[video_path_state, start_time, end_time, log_box],
            outputs=[thumb1, thumb2, log_box]
        )
        end_time.change(
            fn=generate_thumbnails,
            inputs=[video_path_state, start_time, end_time, log_box],
            outputs=[thumb1, thumb2, log_box]
        )
        generate_gif_btn.click(
            fn=create_gif,
            inputs=[video_path_state, start_time, end_time, resolution_slider, fps_slider, speed_slider, loop_slider, log_box],
            outputs=[gif_preview, gif_download, log_box]
        )

    return demo

if __name__ == "__main__":
    interface = build_interface()
    interface.launch()