//
// Created by 崔华根 on 2024/6/17.
//
#include <filesystem>
#include <string>
#include <iostream>
#include <cstdio>
#include <fstream>
#include <array>

std::string exec(const char* cmd) {
    std::array<char, 128> buffer;
    std::string result;
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
    if (!pipe) {
        throw std::runtime_error("popen() failed!");
    }
    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
        result += buffer.data();
    }
    return result;
}

void writeFile(const std::string &filename, const std::string &content) {
    // 创建并打开文件，使用 trunc 模式来清空文件
    std::ofstream file(filename, std::ofstream::out | std::ofstream::trunc);

    // 检查文件是否成功打开
    if (!file) {
        std::cerr << "Failed to open " << filename << std::endl;
        return;
    }

    // 将内容写入文件
    file << content;

    // 关闭文件
    file.close();
}

std::string ReplaceAll(std::string str,
                       const std::string& from,
                       const std::string& to) {
    size_t startPos = 0;
    while((startPos = str.find(from, startPos)) != std::string::npos) {
        str.replace(startPos, from.length(), to);
        startPos += to.length(); // Handles case where 'to' is a substring of 'from'
    }
    return str;
}

void copyFile(std::string sourceFile, std::string destinationFile) {
    std::ifstream src(sourceFile, std::ios::binary);
    std::ofstream dst(destinationFile, std::ios::binary);

    dst << src.rdbuf();
}

void transferCmd(std::string inputFilePath,std::string outputDir,std::string originFileName, int fps, int gop,std::string coder) {
    std::string outputFilePath = outputDir+"out_"+originFileName;
    if (fps>=0) {
        outputFilePath.append("_").append("fps").append(std::to_string(fps));
    }
    if (gop>=0) {
        outputFilePath.append("_").append("gop").append(std::to_string(gop));
    }
    if (!coder.empty()) {
        outputFilePath.append("_").append(coder);
    }
    outputFilePath.append(".mp4");
    std::cout<<"outputFilePath:"<<outputFilePath<<std::endl;

//    std::string ffmpeg_cmd = "ffmpeg -i "+inputFilePath+" -vf \"fps=30\" -g 30  -c:v libx264 -c:a copy -y "+outputFilePath;
    std::string ffmpeg_cmd;
    ffmpeg_cmd.append("ffmpeg -i ");
    ffmpeg_cmd.append(inputFilePath);
    ffmpeg_cmd.append(" ");
    if (fps>=0) {
        ffmpeg_cmd.append("-vf ");
        ffmpeg_cmd.append("\"fps=");
        ffmpeg_cmd.append(std::to_string(fps));
        ffmpeg_cmd.append("\" ");
    }
    if (gop>=0){
        ffmpeg_cmd.append("-g ");
        ffmpeg_cmd.append(std::to_string(30));
        ffmpeg_cmd.append(" ");
    }

    if (coder.empty()) {
        if (fps>=0 || gop>=0){

        }else {
            ffmpeg_cmd.append("-c:v ");
            ffmpeg_cmd.append("copy");
        }
    } else {
        ffmpeg_cmd.append("-c:v ");
        ffmpeg_cmd.append("lib");
        ffmpeg_cmd.append(coder);
    }
    ffmpeg_cmd.append(" ");
    ffmpeg_cmd.append("-c:a copy -y ");
    ffmpeg_cmd.append(outputFilePath);
    std::cout<<"ffmpeg_cmd:"<<ffmpeg_cmd<<std::endl;
    int result = std::system(ffmpeg_cmd.data());
    if (result != 0) {
        // 处理错误
    }
}

int main() {
    std::string inputDir ="/Users/gengen/Downloads/material-design/";
    std::string outputDir="/Users/gengen/Downloads/material-design-out/";
    // 创建文件夹
    std::filesystem::path dirPath(outputDir);
    if (!std::filesystem::create_directory(outputDir)) {
        std::cout << "Failed to create directory."<<outputDir<<std::endl;
//        return 1;
    }
    int index =0;
    for (const auto &entry : std::filesystem::directory_iterator(inputDir)) {
//        std::cout << entry.path().filename().string() << std::endl;
    if (index>0) {
        break;
    }
       std::string  inputPath = entry.path();

        std::cout<<" input:"<<inputPath<<std::endl;

       std::string fileName = entry.path().filename();
        std::cout<<" fileName:"<<inputPath<<std::endl;
        std::string  newFileName=fileName;
        newFileName=ReplaceAll(newFileName,".mp4","");
        newFileName=ReplaceAll(newFileName,".MP4","");
        newFileName=ReplaceAll(newFileName,".mov","");
        newFileName=ReplaceAll(newFileName,".MOV","");
        std::cout<<" newFileName:"<<newFileName<<std::endl;

        outputDir.append(newFileName).append("/");
        if (!std::filesystem::create_directory(outputDir)) {
            std::cout << "Failed to create directory."<<outputDir<<std::endl;
//        return 1;
        }
       std::string fileTextName =newFileName+".txt";

       std::string fileInfoPath = outputDir+fileTextName;
        std::cout<<" fileInfoPath:"<<fileInfoPath<<std::endl;

        std::string cmd = "ffprobe -v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate "+inputPath;
        std::string result = exec(cmd.c_str());

      std::string cmd2="ffprobe -v 0 -select_streams v:0 -show_entries frame=best_effort_timestamp_time,pict_type -of csv=p=0 "+inputPath+" | grep -e 'I'";
        std::string result2 = exec(cmd2.c_str());
//        std::cout << "I帧间隔= "<<result2<<std::endl;

        std::string  finalResult = +"frame rate= "+result+"\n"+"I帧间隔= \n"+result2;
        writeFile(fileInfoPath,finalResult);
        //3. 复制源文件到输出文件夹
        std::string outputOriginFile =outputDir+fileName;
        std::cout<<" outputOriginFile:"<<inputPath<<std::endl;
        copyFile(inputPath,outputOriginFile);


        transferCmd(inputPath,outputDir,newFileName,-1,-1,"");
        transferCmd(inputPath,outputDir,newFileName,-1,30,"");
        transferCmd(inputPath,outputDir,newFileName,-1,30,"x264");
        transferCmd(inputPath,outputDir,newFileName,-1,30,"x265");
        transferCmd(inputPath,outputDir,newFileName,30,30,"");
        transferCmd(inputPath,outputDir,newFileName,30,30,"x264");
        transferCmd(inputPath,outputDir,newFileName,30,30,"x265");
        index++;
    }
    std::cout<<"end of work"<<std::endl;
    return 0;
}