/* NetworkServiceItem.m
 *  
 * Author: Simon Peter
 * Date: January 2026
 *
 */

#import "NetworkServiceItem.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>

@implementation NetworkServiceItem

@synthesize name;
@synthesize type;
@synthesize domain;
@synthesize hostName;
@synthesize port;
@synthesize addresses;
@synthesize netService;
@synthesize resolved;

+ (instancetype)itemWithNetService:(NSNetService *)service
{
  return [[[self alloc] initWithNetService:service] autorelease];
}

- (instancetype)initWithNetService:(NSNetService *)service
{
  self = [super init];
  if (self) {
    self.netService = service;
    self.name = [service name];
    self.type = [service type];
    self.domain = [service domain];
    self.hostName = [service hostName];
    self.port = [service port];
    self.addresses = [service addresses];
    self.resolved = ([service hostName] != nil && [[service hostName] length] > 0);
    manualUsername = nil;
    manualRemotePath = nil;
  }
  return self;
}

- (void)dealloc
{
  [name release];
  [type release];
  [domain release];
  [hostName release];
  [addresses release];
  [netService release];
  [manualUsername release];
  [manualRemotePath release];
  [super dealloc];
}

- (id)copyWithZone:(NSZone *)zone
{
  NetworkServiceItem *copy = [[NetworkServiceItem allocWithZone:zone] init];
  copy.name = self.name;
  copy.type = self.type;
  copy.domain = self.domain;
  copy.hostName = self.hostName;
  copy.port = self.port;
  copy.addresses = [[self.addresses copy] autorelease];
  copy.netService = self.netService;
  copy.resolved = self.resolved;
  [copy setUsername:manualUsername];
  [copy setRemotePath:manualRemotePath];
  return copy;
}

- (NSString *)displayName
{
  NSString *base = name ? name : @"Unknown Service";
  if ([self isSFTPService]) {
    return [base stringByAppendingString:@" (sftp)"];
  } else if ([self isAFPService]) {
    return [base stringByAppendingString:@" (afp)"];
  } else if ([self isWebDAVService]) {
    if ([self isSecureWebDAV]) {
      return [base stringByAppendingString:@" (webdavs)"];
    }
    return [base stringByAppendingString:@" (webdav)"];
  }
  return base;
}

- (NSString *)identifier
{
  return [NSString stringWithFormat:@"%@.%@.%@", name, type, domain];
}

- (BOOL)isLocalMachine
{
  /* Check hostName for well-known loopback / localhost patterns */
  if (hostName) {
    if ([hostName isEqualToString:@"localhost"] ||
        [hostName isEqualToString:@"localhost.localdomain"] ||
        [hostName isEqualToString:@"127.0.0.1"] ||
        [hostName isEqualToString:@"::1"]) {
      return YES;
    }
  }

  /* Check every address for 127.x.x.x (IPv4 loopback) or ::1 (IPv6 loopback) */
  for (NSData *addrData in addresses) {
    const struct sockaddr *addr = (const struct sockaddr *)[addrData bytes];
    if (addr->sa_family == AF_INET) {
      const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
      if ((ntohl(addr4->sin_addr.s_addr) & 0xFF000000) == 0x7F000000) {
        return YES;
      }
    } else if (addr->sa_family == AF_INET6) {
      const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
      if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
        return YES;
      }
    }
  }

  return NO;
}

- (BOOL)isSFTPService
{
  return [type hasPrefix:@"_sftp-ssh."];
}

- (BOOL)isAFPService
{
  return [type hasPrefix:@"_afpovertcp."];
}

- (BOOL)isWebDAVService
{
  return [type hasPrefix:@"_webdav."] || [type hasPrefix:@"_webdavs."];
}

- (BOOL)isSecureWebDAV
{
  return [type hasPrefix:@"_webdavs."];
}

- (NSString *)iconName
{
  /* Use the common Network icon for all network services */
  return @"Network";
}

- (NSString *)remotePath
{
  /* Check if manually set first */
  if (manualRemotePath) {
    return manualRemotePath;
  }
  
  if (!netService) {
    return nil;
  }
  
  /* Get TXT record data from the service */
  NSData *txtData = [netService TXTRecordData];
  if (!txtData || [txtData length] == 0) {
    return nil;
  }
  
  /* Parse TXT record dictionary */
  NSDictionary *txtDict = [NSNetService dictionaryFromTXTRecordData:txtData];
  if (!txtDict) {
    return nil;
  }
  
  /* Look for 'path' key in TXT record */
  NSData *pathData = [txtDict objectForKey:@"path"];
  if (pathData && [pathData length] > 0) {
    NSString *path = [[[NSString alloc] initWithData:pathData 
                                             encoding:NSUTF8StringEncoding] autorelease];
    if (path && [path length] > 0) {
      NSDebugLLog(@"gwspace", @"NetworkServiceItem: Found path in TXT record: %@", path);
      return path;
    }
  }
  
  return nil;
}

- (NSString *)username
{
  /* Check if manually set first */
  if (manualUsername) {
    return manualUsername;
  }
  
  if (!netService) {
    return nil;
  }
  
  /* Get TXT record data from the service */
  NSData *txtData = [netService TXTRecordData];
  if (!txtData || [txtData length] == 0) {
    return nil;
  }
  
  /* Parse TXT record dictionary */
  NSDictionary *txtDict = [NSNetService dictionaryFromTXTRecordData:txtData];
  if (!txtDict) {
    return nil;
  }
  
  /* Look for username in TXT record - try 'u' key (common for SSH/SFTP) */
  NSData *userData = [txtDict objectForKey:@"u"];
  if (userData && [userData length] > 0) {
    NSString *username = [[[NSString alloc] initWithData:userData 
                                                 encoding:NSUTF8StringEncoding] autorelease];
    if (username && [username length] > 0) {
      NSDebugLLog(@"gwspace", @"NetworkServiceItem: Found username in TXT record: %@", username);
      return username;
    }
  }
  
  return nil;
}

- (NSString *)description
{
  return [NSString stringWithFormat:@"<NetworkServiceItem: %@ (%@) at %@:%d>", 
          name, type, hostName, port];
}

- (void)setUsername:(NSString *)user
{
  if (manualUsername != user) {
    [manualUsername release];
    manualUsername = [user copy];
  }
}

- (void)setRemotePath:(NSString *)path
{
  if (manualRemotePath != path) {
    [manualRemotePath release];
    manualRemotePath = [path copy];
  }
}

- (BOOL)isEqual:(id)object
{
  if (![object isKindOfClass:[NetworkServiceItem class]]) {
    return NO;
  }
  NetworkServiceItem *other = (NetworkServiceItem *)object;
  return [[self identifier] isEqual:[other identifier]];
}

- (NSUInteger)hash
{
  return [[self identifier] hash];
}

@end
