#include "ios_bridge.h"
#include <string>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <sstream>
#include <iostream>
#include <chrono>
#include <cstring>
#include <cstdlib>

// やねうら王のヘッダー
#include "../../YaneuraOu/source/types.h"
#include "../../YaneuraOu/source/position.h"
#include "../../YaneuraOu/source/usi.h"
#include "../../YaneuraOu/source/bitboard.h"
#include "../../YaneuraOu/source/search.h"
#include "../../YaneuraOu/source/thread.h"
#include "../../YaneuraOu/source/misc.h"
#include "../../YaneuraOu/source/tt.h"

using namespace std;
using namespace YaneuraOu;

// 外部関数・変数の宣言
extern void is_ready(bool skipCorruptCheck = false);
extern void position_cmd(Position& pos, std::istringstream& is, StateListPtr& states);
extern USI::OptionsMap Options;
extern ThreadPool Threads;

// 名前空間を明示的に使用
using namespace Search;

// エンジンの内部状態
struct YaneuraOuEngine {
    queue<string> responseQueue;
    mutex queueMutex;
    condition_variable queueCV;
    bool isInitialized;
    bool isReady;
    bool shouldStop;
    Position pos;
    StateListPtr states;
    
    YaneuraOuEngine() : isInitialized(false), isReady(false), shouldStop(false) {
        states = StateListPtr(new std::deque<StateInfo>(1));
    }
};

// グローバル変数（エンジンは1つのみ）
static YaneuraOuEngine* g_engine = nullptr;
static mutex g_engineMutex;
static mutex g_cout_mutex;

// 標準出力をキャプチャするためのストリームバッファ
class QueueStreamBuf : public streambuf {
private:
    YaneuraOuEngine* engine;
    string buffer;
    
public:
    QueueStreamBuf(YaneuraOuEngine* eng) : engine(eng) {}
    
protected:
    virtual int overflow(int c) override {
        if (c != EOF) {
            if (c == '\n') {
                if (!buffer.empty()) {
                    lock_guard<mutex> lock(engine->queueMutex);
                    engine->responseQueue.push(buffer);
                    engine->queueCV.notify_one();
                    buffer.clear();
                }
            } else {
                buffer += static_cast<char>(c);
            }
        }
        return c;
    }
    
    virtual int sync() override {
        if (!buffer.empty()) {
            lock_guard<mutex> lock(engine->queueMutex);
            engine->responseQueue.push(buffer);
            engine->queueCV.notify_one();
            buffer.clear();
        }
        return 0;
    }
};

static QueueStreamBuf* g_queueBuf = nullptr;
static streambuf* g_originalCout = nullptr;

// エンジンを作成
extern "C" YaneuraOuEngineHandle yaneuraou_engine_create(void) {
    lock_guard<mutex> lock(g_engineMutex);
    
    if (g_engine != nullptr) {
        return g_engine; // 既に作成済み
    }
    
    g_engine = new YaneuraOuEngine();
    
    // 標準出力をキャプチャ
    g_queueBuf = new QueueStreamBuf(g_engine);
    g_originalCout = cout.rdbuf(g_queueBuf);
    
    return g_engine;
}

// エンジンを破棄
extern "C" void yaneuraou_engine_destroy(YaneuraOuEngineHandle handle) {
    lock_guard<mutex> lock(g_engineMutex);
    
    if (handle == nullptr || handle != g_engine) {
        return;
    }
    
    YaneuraOuEngine* engine = static_cast<YaneuraOuEngine*>(handle);
    engine->shouldStop = true;
    
    // 標準出力を元に戻す
    if (g_originalCout) {
        cout.rdbuf(g_originalCout);
        g_originalCout = nullptr;
    }
    
    if (g_queueBuf) {
        delete g_queueBuf;
        g_queueBuf = nullptr;
    }
    
    delete engine;
    g_engine = nullptr;
}

// USIコマンドを送信
extern "C" int yaneuraou_engine_send_command(YaneuraOuEngineHandle handle, const char* command) {
    if (handle == nullptr || command == nullptr) {
        return -1;
    }
    
    YaneuraOuEngine* engine = static_cast<YaneuraOuEngine*>(handle);
    string cmd(command);
    
    istringstream iss(cmd);
    string token;
    iss >> token;
    
    lock_guard<mutex> lock(g_cout_mutex);
    
    if (token == "usi") {
        if (!engine->isInitialized) {
            // やねうら王の初期化
            USI::init(Options);
            Bitboards::init();
            Position::init();
            init(); // Search::init()
            Threads.set(1);
            engine->isInitialized = true;
        }
        
        cout << "id name YaneuraOu NNUE 9.01" << endl;
        cout << "id author by yaneurao" << endl;
        cout << "option name Threads type spin default 1 min 1 max 1" << endl;
        cout << "option name MultiPV type spin default 1 min 1 max 800" << endl;
        cout << "usiok" << endl;
    }
    else if (token == "isready") {
        if (!engine->isReady) {
            is_ready();
            engine->isReady = true;
        }
        cout << "readyok" << endl;
    }
    else if (token == "setoption") {
        // オプション設定
        string name_token, name, value_token, value;
        iss >> name_token >> name >> value_token >> value;
        
        if (Options.count(name)) {
            Options[name] = value;
        }
    }
    else if (token == "position") {
        // 局面設定
        position_cmd(engine->pos, iss, engine->states);
    }
    else if (token == "go") {
        if (!engine->isReady) {
            cout << "info string error: engine not ready" << endl;
            return -1;
        }
        
        // 探索パラメータを解析
        Search::LimitsType limits;
        limits.startTime = now();
        
        string param;
        while (iss >> param) {
            if (param == "movetime") {
                int ms;
                iss >> ms;
                limits.movetime = ms;
            }
            else if (param == "depth") {
                iss >> limits.depth;
            }
            else if (param == "nodes") {
                iss >> limits.nodes;
            }
        }
        
        // デフォルト値
        if (limits.movetime == 0 && limits.depth == 0) {
            limits.depth = 10;
        }
        
        // 探索を実行
        Threads.start_thinking(engine->pos, limits, engine->states);
        Threads.main()->wait_for_search_finished();
        
        // bestmoveを出力
        Move bestMove = Threads.main()->rootMoves[0].pv[0];
        cout << "bestmove " << USI::move(bestMove) << endl;
    }
    else if (token == "quit") {
        engine->shouldStop = true;
    }
    
    return 0;
}

// エンジンからの応答を受信
extern "C" char* yaneuraou_engine_receive_response(YaneuraOuEngineHandle handle, double timeout_seconds) {
    if (handle == nullptr) {
        return nullptr;
    }
    
    YaneuraOuEngine* engine = static_cast<YaneuraOuEngine*>(handle);
    
    unique_lock<mutex> lock(engine->queueMutex);
    
    // タイムアウト付きで待機
    auto timeout = chrono::milliseconds(static_cast<int>(timeout_seconds * 1000));
    
    if (!engine->queueCV.wait_for(lock, timeout, [engine] {
        return !engine->responseQueue.empty();
    })) {
        return nullptr; // タイムアウト
    }
    
    string response = engine->responseQueue.front();
    engine->responseQueue.pop();
    
    // 文字列をコピーして返す（呼び出し側でfreeする必要あり）
    char* result = static_cast<char*>(malloc(response.length() + 1));
    if (result != nullptr) {
        strcpy(result, response.c_str());
    }
    
    return result;
}

// エンジンが準備完了かチェック
extern "C" int yaneuraou_engine_is_ready(YaneuraOuEngineHandle handle) {
    if (handle == nullptr) {
        return 0;
    }
    
    YaneuraOuEngine* engine = static_cast<YaneuraOuEngine*>(handle);
    return engine->isReady ? 1 : 0;
}
