/*
 * SoulFire
 * Copyright (C) 2026  AlexProgrammerDE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package com.soulfiremc.bootstrap.client.settings;

import com.soulfiremc.server.proxy.ProxyType;
import com.soulfiremc.server.proxy.SFProxy;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;

@Slf4j
public abstract class ProxyParser {
  private static <T> T getIndexOrNull(T[] array, int index) {
    if (index < array.length) {
      return array[index];
    } else {
      return null;
    }
  }

  public static ProxyParser typeParser(ProxyType type) {
    return new ProxyParser() {
      @Override
      public SFProxy parse(String proxyData) {
        // Support user:pass@host:port format
        var atIndex = proxyData.lastIndexOf('@');
        if (atIndex != -1) {
          var userInfo = proxyData.substring(0, atIndex);
          var hostPort = proxyData.substring(atIndex + 1);
          var hostPortSplit = hostPort.split(":");
          if (hostPortSplit.length < 2) {
            throw new IllegalArgumentException("Proxy must have at least a host and a port!");
          }

          var host = hostPortSplit[0];
          var port = Integer.parseInt(hostPortSplit[1]);
          var userInfoSplit = userInfo.split(":");
          var username = getIndexOrNull(userInfoSplit, 0);
          var password = getIndexOrNull(userInfoSplit, 1);

          return new SFProxy(type, new InetSocketAddress(host, port), username, password);
        }

        // Standard host:port:user:pass format
        var split = proxyData.split(":");

        if (split.length < 2) {
          throw new IllegalArgumentException("Proxy must have at least a host and a port!");
        }

        var host = split[0];
        var port = Integer.parseInt(split[1]);
        var username = getIndexOrNull(split, 2);
        var password = getIndexOrNull(split, 3);

        return new SFProxy(type, new InetSocketAddress(host, port), username, password);
      }
    };
  }

  public static ProxyParser uriParser() {
    return new ProxyParser() {
      @Override
      public SFProxy parse(String proxyData) {
        URI uri;
        try {
          uri = URI.create(proxyData).parseServerAuthority();
        } catch (URISyntaxException e) {
          throw new RuntimeException(e);
        }

        var scheme = uri.getScheme();

        if (scheme == null) {
          throw new IllegalArgumentException("Proxy URI must have a scheme!");
        }

        var proxyType = ProxyType.valueOf(scheme.toUpperCase(Locale.ROOT));
        var userInfo = uri.getUserInfo();
        var host = uri.getHost();
        var port = uri.getPort();

        if (host == null || port == -1) {
          throw new IllegalArgumentException("Proxy URI must have a host and a port!");
        }

        String username = null;
        String password = null;

        if (userInfo != null) {
          var split = userInfo.split(":");
          username = getIndexOrNull(split, 0);
          password = getIndexOrNull(split, 1);
        }

        return new SFProxy(proxyType, new InetSocketAddress(host, port), username, password);
      }
    };
  }

  abstract SFProxy parse(String proxyData);
}
