using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    private const string PortFile = "/home/kjh2064/taxbaik_port";
    private static int _fallbackPort = 5003;

    static async Task Main(string[] args)
    {
        // Allow setting fallback port via args
        if (args.Length > 0 && int.TryParse(args[0], out var port))
        {
            _fallbackPort = port;
        }

        var listener = new TcpListener(IPAddress.Loopback, 5001);
        listener.Start();
        Console.WriteLine($"[TaxBaik Proxy] Listening on 127.0.0.1:5001 (Forwarding to target in {PortFile})");

        while (true)
        {
            try
            {
                var client = await listener.AcceptTcpClientAsync();
                _ = HandleClientAsync(client);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[TaxBaik Proxy] Accept error: {ex.Message}");
                await Task.Delay(100);
            }
        }
    }

    private static int GetTargetPort()
    {
        try
        {
            if (File.Exists(PortFile))
            {
                var content = File.ReadAllText(PortFile).Trim();
                if (int.TryParse(content, out var port) && port > 1024 && port < 65535)
                {
                    return port;
                }
            }
        }
        catch { }
        return _fallbackPort;
    }

    private static async Task HandleClientAsync(TcpClient client)
    {
        client.NoDelay = true;
        int targetPort = GetTargetPort();
        using var backend = new TcpClient();
        backend.NoDelay = true;

        try
        {
            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
            await backend.ConnectAsync(IPAddress.Loopback, targetPort, cts.Token);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[TaxBaik Proxy] Failed to connect to backend on port {targetPort}: {ex.Message}");
            client.Close();
            return;
        }

        try
        {
            using var clientStream = client.GetStream();
            using var backendStream = backend.GetStream();

            var toBackend = clientStream.CopyToAsync(backendStream);
            var toClient = backendStream.CopyToAsync(clientStream);

            await Task.WhenAny(toBackend, toClient);
        }
        catch { }
        finally
        {
            client.Close();
            backend.Close();
        }
    }
}
