#include <iostream>
#include <thread>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

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

using namespace std;

static int socket_fd = -1;

// カスタムストリームバッファ（出力用）
class myoutstreambuf : public std::streambuf {
private:
    int fd;
public:
    myoutstreambuf(int fd_) : fd(fd_) {}
    
    virtual int_type overflow(int_type c) {
        if (c != EOF) {
            char z = c;
            if (write(fd, &z, 1) != 1) {
                return EOF;
            }
        }
        return c;
    }
    
    virtual std::streamsize xsputn(const char* s, std::streamsize num) {
        return write(fd, s, num);
    }
};

// カスタムストリームバッファ（入力用）
class myinstreambuf : public std::streambuf {
private:
    int fd;
    static const int BUFFER_SIZE = 1024;
    char buffer[BUFFER_SIZE];
    
public:
    myinstreambuf(int fd_) : fd(fd_) {
        setg(buffer, buffer, buffer);
    }
    
    virtual int_type underflow() {
        if (gptr() < egptr()) {
            return traits_type::to_int_type(*gptr());
        }
        
        int num = read(fd, buffer, BUFFER_SIZE);
        if (num <= 0) {
            return EOF;
        }
        
        setg(buffer, buffer, buffer + num);
        return traits_type::to_int_type(*gptr());
    }
};

// やねうら王エンジンのヘッダー
#include "../../YaneuraOu/source/search.h"
#include "../../YaneuraOu/source/thread.h"
#include "../../YaneuraOu/source/tt.h"
#include "../../YaneuraOu/source/usi.h"
#include "../../YaneuraOu/source/evaluate.h"

// エンジンのメインスレッド
static void yaneuraou_ios_thread_main() {
    // 標準入出力をソケットにリダイレクト
    myoutstreambuf outs(socket_fd);
    myinstreambuf ins(socket_fd);
    auto default_out = std::cout.rdbuf(&outs);
    auto default_in = std::cin.rdbuf(&ins);

    // やねうら王の初期化
    int argc = 1;
    char *argv[] = {(char*)"yaneuraou"};
    
    // CommandLineオブジェクトを作成（v8.60gitではstructとして使用）
    CommandLine cli(argc, argv);
    
    USI::init(Options);
    Bitboards::init();
    Position::init();
    Search::init();
    
    // スレッド数の設定
    size_t thread_num = Options.count("Threads") ? (size_t)Options["Threads"] : 1;
    Threads.set(thread_num);
    
    // 評価関数の初期化
    Eval::init();

    // USIループ
    USI::loop(argc, argv);

    // 標準入出力を元に戻す
    std::cout.rdbuf(default_out);
    std::cin.rdbuf(default_in);
}

// C API: ソケットサーバーを起動してエンジンを開始
extern "C" {
    int yaneuraou_ios_server_start(int port) {
        // ソケットサーバーを作成
        int server_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (server_fd < 0) {
            return -1;
        }
        
        // ソケットオプションを設定
        int opt = 1;
        setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        
        // アドレスを設定
        struct sockaddr_in address;
        address.sin_family = AF_INET;
        address.sin_addr.s_addr = inet_addr("127.0.0.1");
        address.sin_port = htons(port);
        
        // バインド
        if (::bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
            close(server_fd);
            return -2;
        }
        
        // リッスン
        if (listen(server_fd, 1) < 0) {
            close(server_fd);
            return -3;
        }
        
        // クライアント接続を待機
        socket_fd = accept(server_fd, NULL, NULL);
        close(server_fd);
        
        if (socket_fd < 0) {
            return -4;
        }
        
        // エンジンスレッドを起動
        std::thread engine_thread(yaneuraou_ios_thread_main);
        engine_thread.detach();
        
        return 0;
    }
    
    // ソケットを閉じる
    void yaneuraou_ios_server_stop() {
        if (socket_fd >= 0) {
            close(socket_fd);
            socket_fd = -1;
        }
    }
}
