import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.jetbrains.annotations.NotNull;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DiscordDownloadBot extends ListenerAdapter {

    // 🔴 토큰 확인
    private static final String BOT_TOKEN = "MTQ0Nzg1NjI1NTY4NjE0ODEzOA.GpvmOr.KRTrSGh1GrmlF_oHY1brKZbAXb3erfHBlPXHEI";

    private static final String YTDLP_PATH = System.getProperty("user.dir") + File.separator + "yt-dlp.exe";
    private static final String BASE_DOWNLOAD_DIR = System.getProperty("user.dir") + File.separator + "Downloads";

    private final ExecutorService executor = Executors.newFixedThreadPool(3);
    private static final Map<String, String> pendingUrls = new HashMap<>();
    private static final Map<String, Boolean> isCreatingFolder = new HashMap<>();

    public static void main(String[] args) {
        new File(BASE_DOWNLOAD_DIR).mkdirs();
        try {
            JDABuilder.createDefault(BOT_TOKEN)
                    .enableIntents(GatewayIntent.MESSAGE_CONTENT)
                    .addEventListeners(new DiscordDownloadBot())
                    .build();
            System.out.println("🤖 봇 실행 완료! (더블 탭 전략)");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onMessageReceived(@NotNull MessageReceivedEvent event) {
        if (event.getAuthor().isBot()) return;
        String userId = event.getAuthor().getId();
        String message = event.getMessage().getContentRaw();

        if (isCreatingFolder.getOrDefault(userId, false)) {
            createNewFolderAndDownload(event, message);
            return;
        }

        String foundUrl = extractUrl(message);
        if (foundUrl != null) {
            pendingUrls.put(userId, foundUrl);
            sendFolderSelectionMenu(event);
        }
    }

    private void sendFolderSelectionMenu(MessageReceivedEvent event) {
        File baseDir = new File(BASE_DOWNLOAD_DIR);
        File[] directories = baseDir.listFiles(File::isDirectory);
        StringSelectMenu.Builder menuBuilder = StringSelectMenu.create("folder-select").setPlaceholder("📂 저장할 폴더를 선택하세요");

        if (directories != null) {
            for (File dir : directories) {
                if (menuBuilder.getOptions().size() >= 24) break;
                menuBuilder.addOption("📂 " + dir.getName(), dir.getName());
            }
        }
        menuBuilder.addOption("➕ 새 폴더 만들기", "create_new_folder");
        event.getChannel().sendMessage("영상 링크를 확인했습니다! **어디에 저장할까요?**").addActionRow(menuBuilder.build()).queue();
    }

    @Override
    public void onStringSelectInteraction(StringSelectInteractionEvent event) {
        if (!event.getComponentId().equals("folder-select")) return;
        String selectedValue = event.getValues().get(0);
        String userId = event.getUser().getId();
        String url = pendingUrls.get(userId);

        if (url == null) {
            event.reply("❌ 링크 정보가 만료되었습니다.").setEphemeral(true).queue();
            return;
        }

        if (selectedValue.equals("create_new_folder")) {
            isCreatingFolder.put(userId, true);
            event.reply("📝 **새 폴더 이름을 입력해주세요.**").setEphemeral(true).queue();
        } else {
            event.reply("✅ **" + selectedValue + "** 폴더에 저장을 시작합니다!").queue();
            String targetPath = BASE_DOWNLOAD_DIR + File.separator + selectedValue;
            executor.submit(() -> processDownload(url, event.getMessageChannel(), targetPath));
            pendingUrls.remove(userId);
        }
    }

    private void createNewFolderAndDownload(MessageReceivedEvent event, String folderName) {
        String userId = event.getAuthor().getId();
        folderName = folderName.replaceAll("[^a-zA-Z0-9가-힣_\\-]", "");
        if (folderName.isEmpty()) folderName = "NewFolder";
        String newFolderPath = BASE_DOWNLOAD_DIR + File.separator + folderName;
        new File(newFolderPath).mkdirs();

        String url = pendingUrls.get(userId);
        if (url != null) {
            event.getChannel().sendMessage("📥 **" + folderName + "** 폴더에 다운로드 시작!").queue();
            executor.submit(() -> processDownload(url, event.getChannel(), newFolderPath));
        }
        isCreatingFolder.remove(userId);
        pendingUrls.remove(userId);
    }

    // ⬇️ [최종 전략] 1차(영상) 시도 -> 실패시 -> 2차(사진) 시도
    private void processDownload(String url, net.dv8tion.jda.api.entities.channel.middleman.MessageChannel channel, String saveDir) {
        Message progressMessage = null;
        try {
            progressMessage = channel.sendMessage("⏳ **다운로드 시도 중...**").complete();

            // 1. URL에서 번호 뽑기
            String targetIndexStr = getImgIndex(url);
            String targetIndex = (targetIndexStr != null) ? targetIndexStr : "1";
            System.out.println("🎯 타겟 번호: " + targetIndex + "번");

            // ==========================================
            // 👊 1타: 동영상이라고 가정하고 다운로드 시도
            // ==========================================
            boolean isVideoSuccess = tryDownloadAsVideo(url, saveDir, targetIndex);

            if (isVideoSuccess) {
                progressMessage.editMessage("✅ **동영상 다운로드 완료!**\n📂 폴더: `" + new File(saveDir).getName() + "`").queue();
                return;
            }

            System.out.println("⚠️ 동영상 다운로드 실패(사진인듯). 2차 시도 시작...");

            // ==========================================
            // 👊 2타: 사진이라고 가정하고 다운로드 시도
            // ==========================================
            boolean isImageSuccess = tryDownloadAsImage(url, saveDir, targetIndex);

            if (isImageSuccess) {
                progressMessage.editMessage("✅ **사진 다운로드 완료!**\n📂 폴더: `" + new File(saveDir).getName() + "`").queue();
            } else {
                progressMessage.editMessage("❌ **최종 실패.** (쿠키 만료 또는 게시물 삭제됨)").queue();
            }

        } catch (Exception e) {
            if (progressMessage != null) progressMessage.editMessage("🔥 오류: " + e.getMessage()).queue();
            e.printStackTrace();
        }
    }

    // 🎥 1타: 동영상 모드 (Index 지정)
    private boolean tryDownloadAsVideo(String url, String saveDir, String index) {
        try {
            List<String> cmdList = new ArrayList<>();
            cmdList.add(YTDLP_PATH);
            cmdList.add("--cookies");
            cmdList.add("cookies.txt");
            cmdList.add("--user-agent"); // 동영상은 PC UA가 더 안정적일 때가 있음
            cmdList.add("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");

            // 🎯 인덱스 지정
            cmdList.add("--playlist-items");
            cmdList.add(index);

            // 포맷 강제 (동영상이 아니면 여기서 에러 나고 죽음 -> catch로 넘어감)
            cmdList.add("-f");
            cmdList.add("bestvideo+bestaudio/best");
            cmdList.add("--merge-output-format");
            cmdList.add("mp4");

            cmdList.add("-o");
            cmdList.add(saveDir + File.separator + "%(title)s_%(id)s_Video" + index + ".%(ext)s");
            cmdList.add(url);

            System.out.println("🚀 [1타] 동영상 시도: " + index + "번");

            ProcessBuilder pb = new ProcessBuilder(cmdList);
            pb.redirectErrorStream(true);
            Process process = pb.start();

            // 로그 읽기 (성공 여부 판단)
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            boolean success = false;
            while ((line = reader.readLine()) != null) {
                // System.out.println("[Video] " + line); // 너무 시끄러우면 주석 처리
                if (line.contains("100%") || line.contains("Destination")) {
                    success = true;
                }
            }
            process.waitFor();

            // 파일이 진짜 생겼는지 확인
            if (success) return true;

            // yt-dlp가 성공했다고 구라칠 수도 있으니 파일 확인
            return checkFileExists(saveDir, "Video" + index);

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 🖼️ 2타: 사진 모드 (Index 지정 + 썸네일 강제 저장)
    private boolean tryDownloadAsImage(String url, String saveDir, String index) {
        try {
            List<String> cmdList = new ArrayList<>();
            cmdList.add(YTDLP_PATH);
            cmdList.add("--cookies");
            cmdList.add("cookies.txt");
            cmdList.add("--user-agent"); // 사진은 모바일 UA가 짱임
            cmdList.add("Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1");

            // 🎯 인덱스 지정
            cmdList.add("--playlist-items");
            cmdList.add(index);

            // ⭐ [핵심] "동영상 말고 썸네일(사진)을 파일로 써라"
            cmdList.add("--write-thumbnail");
            cmdList.add("--skip-download"); // 동영상 다운로드는 생략 (어차피 없으니까)
            cmdList.add("--convert-thumbnails");
            cmdList.add("jpg");

            cmdList.add("--ignore-errors"); // 에러 무시 (No video 에러 씹기)

            cmdList.add("-o");
            // 파일명에 ImageTag를 붙여서 식별
            cmdList.add(saveDir + File.separator + "%(title)s_%(id)s_Image" + index + ".%(ext)s");
            cmdList.add(url);

            System.out.println("🚀 [2타] 사진 시도: " + index + "번");

            ProcessBuilder pb = new ProcessBuilder(cmdList);
            pb.redirectErrorStream(true);
            Process process = pb.start();

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                // System.out.println("[Image] " + line);
            }
            process.waitFor();

            // 파일이 생겼는지 확인 (이게 제일 확실함)
            return checkFileExists(saveDir, "Image" + index);

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 파일 생성 확인 함수
    private boolean checkFileExists(String saveDir, String keyword) {
        File dir = new File(saveDir);
        File[] files = dir.listFiles();
        if (files == null) return false;

        for (File f : files) {
            // 방금 다운로드 시도한 파일(키워드 포함)이 존재하면 성공
            if (f.getName().contains(keyword)) {
                return true;
            }
        }
        return false;
    }

    private String extractUrl(String text) {
        Matcher matcher = Pattern.compile("(https?://\\S+)").matcher(text);
        if (matcher.find()) {
            String found = matcher.group(1);
            if (found.contains("youtube.com") || found.contains("youtu.be") || found.contains("instagram.com")) {
                return found;
            }
        }
        return null;
    }

    private String getImgIndex(String url) {
        try {
            Matcher m = Pattern.compile("[?&]img_index=(\\d+)").matcher(url);
            if (m.find()) return m.group(1);
        } catch (Exception e) { /* 무시 */ }
        return null;
    }
    ////
}