#!/usr/bin/perl -w

use strict;
no warnings qw(redefine);
use lib "/home/rt/rt/local/lib";
use lib "/home/rt/rt/lib";
use lib "/home/rt/rt/etc";
use RT;
use RT::Interface::CLI qw( CleanEnv );
use RT::User;
use utf8;
use Data::Dumper;

# Disable STDOUT buffering
$| = 1;

CleanEnv();
RT::LoadConfig();
RT->Config->Set('LogToSTDERR' => 'warning');
RT::Init();

# Disable lifecycle transition checking
use RT::Lifecycle;
*RT::Lifecycle::IsValid = sub {
	return 1;
};
*RT::Lifecycle::IsTransition = sub {
	return 1;
};

# Disable scrips
use RT::Transaction;
my $old_create = \&RT::Transaction::Create;
*RT::Transaction::Create = sub {
	my $self = shift;
	my %args = @_;
	$args{ActivateScrips} = 0;
	return $old_create->($self, %args);
};

my ($val, $msg);
my $start_time = time;


RT->Config->Set('DatabaseName', 'icw');
my $icw = RT::Handle->new( RT->SystemUser );
$icw->Connect;
my $icw_dbh = $icw->dbh;
$icw_dbh->do("SET CLIENT_ENCODING TO 'UTF-8'");
$icw_dbh->{pg_enable_utf8} = 1;

my $users_map;
my $assets_map;
my $tickets_map;

my @privileged_users = qw(xxxx yyyy);

my $assets_parents;
my $users_parents;

$assets_parents->{'Sous-catégorie'} = 'Catégorie';
$assets_parents->{'Modèle'} = 'Marque';

RT->Logger->debug("Importing users");
my $users_query = 'SELECT 
    amempldept.lempldeptid AS "id",
    trim(both from amempldept.userlogin) AS "Name", 
    trim (both from COALESCE(amempldept.firstname, \'\') || \' \' || COALESCE(amempldept.name,\'\') ) AS "RealName",
    trim(both from amempldept.mrmrs) AS "CF.{Civilité}", 
    trim(both from amempldept.phone) AS "WorkPhone", 
    trim(both from amempldept.email) AS "EmailAddress", 
    trim(both from amempldept.field1) AS "CF.{Service}", 
    trim(both from amempldept.title) AS "CF.{Fonction}", 
    trim(both from amempldept.field2) AS "CF.{VIP}", 
    trim(both from amlocation.address1) AS "Address1", 
    trim(both from amlocation.address2) AS "Address2", 
    trim(both from amlocation.zip) AS "Zip", 
    trim(both from amlocation.city) AS "City", 
    trim(both from amlocation.country) AS "Country", 
    trim(both from amlocation.field1) AS "CF.{Téléphone localisation}", 
    trim(both from amcomment.memcomment) AS "Comments"
	FROM amempldept
	LEFT OUTER JOIN amlocation
		ON ( amempldept.llocaid = amlocation.llocaid )
	LEFT OUTER JOIN amcomment
		ON ( amcomment.tablename = \'amEmplDept\' AND amEmplDept.lcommentid = amcomment.lcommentid )';

# Pre-load customfields id/type for performances
my $user_customfields;
foreach my $cf_name ( ( 'Civilité', 'Service', 'Fonction', 'VIP', 'Téléphone localisation' ) ) {
	my $CustomField = RT::CustomField->new( RT->SystemUser );
	$CustomField->LoadByName( Name => $cf_name, LookupType => 'RT::User' );
	unless ( $CustomField && $CustomField->id ) {
		RT->Logger->crit("Unable to load CF $cf_name");
		die;
	}
	$user_customfields->{$cf_name}->{id} = $CustomField->id;
	$user_customfields->{$cf_name}->{Type} = $CustomField->Type;
}

my $users_sth = $icw_dbh->prepare($users_query);
$users_sth->execute();
my $total = $users_sth->rows;
RT->Logger->debug("Found $total users");
my $i = 0;
while ( my $icw_user = $users_sth->fetchrow_hashref('NAME')) {
	$i++;
	printf("\r%0.2f %%", 100 * $i / $total);

	my $icw_id = delete($icw_user->{'id'});
    next unless ( $icw_id );

	if ( $users_map->{$icw_id} ) {
		RT->Logger->warning("User $icw_id already seen as ".$users_map->{$icw_id});
		next;
	}
	unless ( $icw_user->{'Name'} ) {
		unless ( $icw_user->{'RealName'} ) {
			RT->Logger->crit("User without Name or RealName: ".$icw_id);
			next;
		}
		$icw_user->{'Name'} = lc $icw_user->{'RealName'};
        $icw_user->{'Name'} =~ s/\s+/_/g;
        $icw_user->{'Name'} =~ s/^\///g;
        $icw_user->{'Name'} =~ s/\/$//g;
        $icw_user->{'Name'} =~ s/\//_/g;
        $icw_user->{'Name'} =~ s/_?&_?/_et_/g;
        $icw_user->{'Name'} =~ s/[,'"*¨()]//g;
        $icw_user->{'Name'} =~ s/[áàâäã]/a/gi;
        $icw_user->{'Name'} =~ s/[éèêë¿]/e/gi;
        $icw_user->{'Name'} =~ s/[íìîï¿]/i/gi;
        $icw_user->{'Name'} =~ s/[óòôöõ]/o/gi;
        $icw_user->{'Name'} =~ s/[úùûü¿]/u/gi;
        $icw_user->{'Name'} =~ s/[ç]/c/gi;

		RT->Logger->warning("User without name: $icw_id, trying firstname_name : ".$icw_user->{'Name'});
		unless ( $icw_user->{'Name'} =~ m/^[a-z0-9_.-]+$/ ) {
			RT->Logger->crit("Generated Name for user $icw_id, has wrong chars : ".$icw_user->{'Name'});
			next;
		}
	}

    if ( $icw_user->{'EmailAddress'} && $icw_user->{'EmailAddress'} !~ m/^.+\@.+$/ ) {
        RT->Logger->warning("User with wrong email, skipping email address: ".$icw_user->{'EmailAddress'});
        delete $icw_user->{'EmailAddress'};
    }

	# CustomFields are not supported by RT::User->Create
	my $customfields;
	foreach my $key (keys %{$icw_user}) {
		if ( $key =~ m/^CF\.{(.*)}$/i ) {
			$customfields->{$1} = delete $icw_user->{$key};
		}
	}

	my $rt_user = RT::User->new( RT->SystemUser );
	($val, $msg) = $rt_user->Load($icw_user->{'Name'});
	unless ( $val ) {
		RT->Logger->debug("Adding user ".$icw_user->{'Name'});
		($val, $msg) = $rt_user->Create(
			Name => $icw_user->{'Name'},
			_RecordTransaction => 0,
		);
		unless ( $val ) {
			RT->Logger->crit("Unable to add user ".$icw_user->{'Name'}.": $msg");
			next;
		}
	}

	$users_map->{$icw_id} = $rt_user->id;
	RT->Logger->debug("Updating user ".$icw_user->{'Name'}.", icw id: ".$icw_id.", rt id: ".$rt_user->id );
	delete $icw_user->{'Name'};
	foreach my $attr ( keys %{$icw_user} ) {
		next unless ( $icw_user->{$attr} );
		next if ( $rt_user->$attr && $icw_user->{$attr} && $rt_user->$attr eq $icw_user->{$attr} );
		my $method = 'Set'.$attr;
		($val, $msg) = $rt_user->$method($icw_user->{$attr});
		unless ( $val ) {
			RT->Logger->warning("Unable to update attribute $attr for user ".$rt_user->Name.": $msg");
		}
	}

	foreach my $cf_name (keys %{$customfields}) {
		my $value = $customfields->{$cf_name};
		next unless ( $value );
                $value =~ s/\r//g;
		my $category = undef;
		if ( $users_parents->{$cf_name} ) {
			$category = $customfields->{$users_parents->{$cf_name}};
		}
	
		if ( $user_customfields->{$cf_name}->{Type} eq 'Select' ) {
			push @{$user_customfields->{$cf_name}->{Values}}, { Name => $value, Category => $category } unless ( grep { $_->{Name} eq $value } @{$user_customfields->{$cf_name}->{Values}} );
		}
	
		#my $current_value = $rt_user->FirstCustomFieldValue( $user_customfields->{$cf_name}->{id} );
		#next if ( $current_value && $value && $current_value eq $value );
	
		($val, $msg) = $rt_user->AddCustomFieldValue( Field => $user_customfields->{$cf_name}->{id}, Value => $value, RecordTransaction => 0 );
		unless ( $val ) {
			RT->Logger->warning("Unable to set value of customfield $cf_name for user ".$rt_user->Name.": $msg");
		}
	}

    # Enable and set privileged if needed
    $rt_user->SetDisabled(0) if ( $rt_user->Disabled );
    if ( grep { $rt_user->Name eq $_ } @privileged_users ) {
        $rt_user->SetPrivileged(1);
    }

}
$users_sth->finish();

# Update user customfields values

foreach my $cf_name ( keys %{$user_customfields} ) {
	next unless ( $user_customfields->{$cf_name}->{Type} eq 'Select' );
	next unless ( $user_customfields->{$cf_name}->{Values} );
	next unless ( scalar @{$user_customfields->{$cf_name}->{Values}} );

	my $CustomField = RT::CustomField->new( RT->SystemUser );
	$CustomField->Load($user_customfields->{$cf_name}->{id});
	my $Values = $CustomField->Values;
	while (my $Value = $Values->Next) {
		$Value->Delete;
	}
	foreach my $value (@{$user_customfields->{$cf_name}->{Values}}) {
		$CustomField->AddValue( %{$value} );
	}
}

RT->Logger->debug("Importing assets");
# FIXME: amcomment may result in duplicate assets
my $assets_query = 'SELECT 
    amasset.lastid AS "id",
    amasset.seassignment AS "Status",
    trim(both from amcategory.fullname) AS "CF.{Catégorie/Sous-catégorie}",
    trim(both from amasset.brand) AS "CF.{Marque}",
    trim(both from amproduct.model) AS "CF.{Modèle}",
    trim(both from amasset.assettag) AS "Name",
    trim(both from amasset.serialno) AS "CF.{N° de série}",
    trim(both from amasset.status) AS "CF.{État}",
    trim(both from amstock.name) AS "CF.{Stock}",
    amasset.dinstall AS "CF.{Date d´installation}",
    amasset.dtlastscan AS "CF.{Date de dernier inventaire}",
    amasset.dwarrend AS "CF.{Date de fin garantie}",
    trim(both from amasset.computername) AS "CF.{Nom de l´ordinateur}",
    trim(both from amasset.field1) AS "CF.{Champs 1}",
    trim(both from amasset.field2) AS "CF.{Champs 2}",
    trim(both from amasset.field3) AS "CF.{Champs 3}",
    amasset.lmaintcntrid AS "Owner",
    amasset.luserid AS "HeldBy",
    trim(both from amcomment.memcomment) AS "CF.{Commentaire}"
	FROM amasset
	LEFT OUTER JOIN amcategory
		ON amasset.lcategid = amcategory.lcategid
	LEFT OUTER JOIN amproduct
		ON amasset.lprodid = amproduct.lprodid
	LEFT OUTER JOIN amcomment
		ON ( amcomment.tablename=\'amAsset\' AND amcomment.lcommentid=amasset.lcommentid )
	LEFT OUTER JOIN amstock
		ON amasset.lstockid = amstock.lstockid';

my $asset_status_map = {
	'0' => 'Dans le parc',
	'1' => 'Non affecté',
	'2' => 'Sortie du parc',
	'3' => 'En attente affectation',
};

# Pre-load customfields id/type for performances
my $asset_customfields;
foreach my $cf_name ( ( "Catégorie", "Sous-catégorie", "Marque", "Modèle", "N° de série", "État", "Stock", "Date d´installation", "Date de dernier inventaire", "Date de fin garantie", "Nom de l´ordinateur", "Champs 1", "Champs 2", "Champs 3", "Commentaire" ) ) {
	my $CustomField = RT::CustomField->new( RT->SystemUser );
	$CustomField->LoadByName( Name => $cf_name, LookupType => 'RT::Catalog-RT::Asset' );
	unless ( $CustomField && $CustomField->id ) {
		RT->Logger->crit("Unable to load CF $cf_name");
		die;
	}
	$asset_customfields->{$cf_name}->{id} = $CustomField->id;
	$asset_customfields->{$cf_name}->{Type} = $CustomField->Type;
}

my $assets_sth = $icw_dbh->prepare($assets_query);
$assets_sth->execute();
$total = $assets_sth->rows;
RT->Logger->debug("Found $total assets");
$i = 0;
while ( my $icw_asset = $assets_sth->fetchrow_hashref('NAME')) {
	$i++;
	printf("\r%0.2f %%", 100 * $i / $total);
	
	my $icw_id = delete($icw_asset->{'id'});
    next unless (defined $icw_id && $icw_id != 0);
	if ( $assets_map->{$icw_id} ) {
		RT->Logger->warning("Asset $icw_id already seen as ".$assets_map->{$icw_id});
		next;
	}
	unless ( $icw_asset->{'Name'} ) {
		RT->Logger->warning("Asset without name: ".$icw_id.", using id as Name");
		# FIXME
		$icw_asset->{'Name'} = "Bien ".$icw_id;
	}

	if ( $icw_asset->{'Name'} =~ m/^\d+$/ ) {
		# FIXME: normer
		$icw_asset->{'Name'} = "N".$icw_asset->{'Name'};
	}
	my $status = $asset_status_map->{$icw_asset->{'Status'}};
	$icw_asset->{'Status'} = $status;

	foreach my $role (qw(Owner HeldBy)) {
		unless ( $icw_asset->{$role} ) {
			delete ($icw_asset->{$role});
			next;
		}
		my $rt_role_id = $users_map->{$icw_asset->{$role}};
		unless ( $rt_role_id ) {
			RT->Logger->warning("No mapping found for role $role: ".$icw_asset->{$role}.", asset ".$icw_asset->{'Name'} );
			delete ($icw_asset->{$role});
		} else {
			$icw_asset->{$role} = $rt_role_id;
		}
	}

	# CustomFields are handled after creation/update
	my $customfields;
	foreach my $key (keys %{$icw_asset}) {
		if ( $key =~ m/^CF\.{(.*)}$/i ) {
			my $customfield = $1;
			my $value = delete ($icw_asset->{$key});
			next unless ( $value );
                        $value =~ s/\r//g;
			if ( $customfield =~ m/^Catégorie\/Sous-catégorie$/ ) {
				# $value shoud be /Catégorie/Sous-Catégorie/
				$value =~ s/^\///;
				$value =~ s/\/$//;
				my ($category, $subcategory) = split /\//, $value;
				$customfields->{'Catégorie'} = $category || '';
				$customfields->{'Sous-catégorie'} = $subcategory || '';
			} else {
				$customfields->{$customfield} = $value;
			}
		}
	}

	my $rt_asset = RT::Asset->new( RT->SystemUser );

	# FIXME: better to load by icw id
	# Need to record icw id
	#($val, $msg) = $rt_asset->Load($icw_asset->{'Name'});
	#unless ( $val ) {
		RT->Logger->debug("Adding asset ".$icw_id);
		($val, $msg) = $rt_asset->Create(
			Catalog => 'Informatique',
			Name => $icw_asset->{'Name'},
			_RecordTransaction => 0,
		);
		unless ( $val ) {
			RT->Logger->crit("Unable to add asset ".$icw_asset->{'Name'}.": $msg");
			next;
		}
	#}
	$assets_map->{$icw_id} = $rt_asset->id;
	RT->Logger->debug("Updating asset ".$icw_asset->{'Name'}.", icw id: ".$icw_id.", rt id: ".$rt_asset->id );
	delete ($icw_asset->{'Name'});
	foreach my $attr ( keys %{$icw_asset} ) {
		next unless ( $icw_asset->{$attr} );
		next if ( $rt_asset->$attr eq $icw_asset->{$attr} );
		if ( $attr eq 'Owner' || $attr eq 'HeldBy' ) {
			my $role_group = $rt_asset->RoleGroup($attr);
			#unless ( $role_group->HasMember($icw_asset->{$attr}) ) {
				# No acls checks because old owners may not have right to own tickets on this queue
				($val, $msg) = $role_group->_AddMember(
					PrincipalId => $icw_asset->{$attr},
					InsideTransaction => 1,
					RecordTransaction => 0,
					Object => $rt_asset, );
			#}
		} else {
			my $method = 'Set'.$attr;
			($val, $msg) = $rt_asset->$method($icw_asset->{$attr});
		}
		unless ( $val ) {
			RT->Logger->warning("Unable to update attribute $attr for asset ".$rt_asset->Name.": $msg");
		}
	}

	foreach my $cf_name (keys %{$customfields}) {
		my $value = $customfields->{$cf_name};
		next unless ( $value );
		my $category = undef;
		if ( $assets_parents->{$cf_name} ) {
			$category = $customfields->{$assets_parents->{$cf_name}};
		}

		if ( $asset_customfields->{$cf_name}->{Type} eq 'Select' ) {
			push @{$asset_customfields->{$cf_name}->{Values}}, { Name => $value, Category => $category } unless ( grep { $_->{Name} eq $value } @{$asset_customfields->{$cf_name}->{Values}} );
		}
	
		#my $current_value = $rt_asset->FirstCustomFieldValue( $asset_customfields->{$cf_name}->{id} );
		#next if ( $current_value && $value && $current_value eq $value );
	
		($val, $msg) = $rt_asset->AddCustomFieldValue( Field => $asset_customfields->{$cf_name}->{id}, Value => $value, RecordTransaction => 0 );
		unless ( $val ) {
			RT->Logger->warning("Unable to set value of customfield $cf_name for asset ".$rt_asset->Name.": $msg");
		}
	}
}
$assets_sth->finish();

# Update asset customfields values

foreach my $cf_name ( keys %{$asset_customfields} ) {
	next unless ( $asset_customfields->{$cf_name}->{Type} eq 'Select' );
	next unless ( $asset_customfields->{$cf_name}->{Values} );
	next unless ( scalar @{$asset_customfields->{$cf_name}->{Values}} );

	my $CustomField = RT::CustomField->new( RT->SystemUser );
	$CustomField->Load($asset_customfields->{$cf_name}->{id});
	my $Values = $CustomField->Values;
	while (my $Value = $Values->Next) {
		$Value->Delete;
	}
	foreach my $value (@{$asset_customfields->{$cf_name}->{Values}}) {
		$CustomField->AddValue( %{$value} );
	}
}


RT->Logger->debug("Importing tickets");
my $tickets_query = 'SELECT
        amticket.lticketid AS "id",
        amticket.sestatus AS "Status",
        amticket.dtopened AS "Created",
        amticket.dtlastmodif AS "LastUpdated",
        amticket.lcontactid AS "Requestor",
        amticket.lassigneeid AS "Owner",
        amticket.dtresollimit AS "Due",
        amticket.dtend AS "Resolved",
        trim(both from amticket.resolcode) AS "CF.{Code de résolution}",
        trim(both from amticket.fullname) AS "Subject",
        trim(both from amticket.notes) AS "CF.{Notes}",
        amticket.lastid AS "Asset",
        trim(both from amproblemclass.fullname) AS "CF.{Type/Catégorie/Domaine/Sous-domaine}",
        trim(both from amemplgroup.name) AS "Queue",
        trim(both from amseverity.name) AS "CF.{Gravité}",
        trim(both from rh.valstring) AS "CF.{Résolution Helpdesk}"
        FROM amticket
        LEFT OUTER JOIN amproblemclass
                ON amticket.lpbclassid = amproblemclass.lpbclassid
        LEFT OUTER JOIN amemplgroup
                ON amticket.lgroupid = amemplgroup.lgroupid
        LEFT OUTER JOIN amseverity
                ON amticket.lseverityid = amseverity.lseverityid
        LEFT OUTER JOIN ( 
                SELECT  amfvticket.lticketid AS lticketid, amfvticket.valstring AS valstring 
                FROM amfvticket, amfeature 
                    WHERE amfvticket.lfeatid=amfeature.lfeatid AND amfeature.textlabel=\'Résolution HelpDesk\' 
                ) rh 
                ON ( rh.lticketid=amticket.lticketid )';


my $ticket_comments_query = 'SELECT 
    amcomment.dtlastmodif AS "Created",
    trim(both from amcomment.memcomment) AS "Content"
	FROM amcomment, amticket
	WHERE
		amcomment.tablename = \'amTicket\'
		AND amcomment.lcommentid = amticket.ldescid
		AND amticket.lticketid = ?';

my $ticket_status_map = {
	0 => 'new',
	1 => 'open',
	2 => 'resolved',
	3 => 'closed',
	4 => 'closed and validated',
};

my $ticket_queues_map = {
	'ICW group' => 'RT queue',
};

my $tickets_parents = {
	'Sous-domaine' => 'Domaine',
	'Domaine' => 'Catégorie',
	'Catégorie' => 'Type',
};

# Pre-load customfields id/type for performances
my $ticket_customfields;
my $Queue = RT::Queue->new( RT->SystemUser );
$Queue->Load('HelpDesk');
foreach my $cf_name ( ( 'Type', 'Catégorie', 'Domaine', 'Sous-domaine', 'Code de résolution', 'Notes', 'Gravité', 'Résolution Helpdesk', 'Numéro de ticket ICW' ) ) {
	my $CustomField = RT::CustomField->new( RT->SystemUser );
	$CustomField->LoadByName( Name => $cf_name, Queue => $Queue->id );
	unless ( $CustomField && $CustomField->id ) {
		RT->Logger->crit("Unable to load CF $cf_name");
		die;
	}
	$ticket_customfields->{$cf_name}->{id} = $CustomField->id;
	$ticket_customfields->{$cf_name}->{Type} = $CustomField->Type;
}


my $tickets_sth = $icw_dbh->prepare($tickets_query);
my $ticket_comments_sth = $icw_dbh->prepare($ticket_comments_query);
$tickets_sth->execute();
$total = $tickets_sth->rows;
RT->Logger->debug("Found $total tickets");
$i = 0;
while ( my $icw_ticket = $tickets_sth->fetchrow_hashref('NAME')) {
	$i++;
	printf("\r%0.2f %%", 100 * $i / $total);
	
	my $icw_id = delete $icw_ticket->{'id'};
    next unless (defined $icw_id && $icw_id != 0);
	if ( $tickets_map->{$icw_id} ) {
		RT->Logger->warning("Ticket $icw_id already seen as ".$tickets_map->{$icw_id});
		next;
	}

	my $status = $ticket_status_map->{$icw_ticket->{'Status'}};
	$icw_ticket->{'Status'} = $status;

	foreach my $role (qw(Owner Requestor)) {
		unless ( $icw_ticket->{$role} ) {
			delete ($icw_ticket->{$role});
			next;
		}
		my $rt_role_id = $users_map->{$icw_ticket->{$role}};
		unless ( $rt_role_id ) {
			RT->Logger->warning("No mapping found for role $role: ".$icw_ticket->{$role}.", ticket ".$icw_id);
			delete ($icw_ticket->{$role});
		} else {
			$icw_ticket->{$role} = $rt_role_id;
		}
	}

	# Assets mapping
	if ( $icw_ticket->{Asset} ) {
		my $rt_asset = $assets_map->{$icw_ticket->{Asset}};
		if ( $rt_asset ) {
			$icw_ticket->{RefersTo} = $rt_asset;
		} else {
			RT->Logger->warning("No mapping found for asset ".$icw_ticket->{Asset}.", ticket ".$icw_id);
		}	
		delete $icw_ticket->{Asset};
	}

	# Queues mapping
    unless ( $icw_ticket->{'Queue'} ) {
        $icw_ticket->{'Queue'} = 'Obselettes';
    }
	unless ( $ticket_queues_map->{$icw_ticket->{'Queue'}} ) {
		RT->Logger->error("No mapping found for queue ".$icw_ticket->{'Queue'}.", ticket ".$icw_id);
		next;
	}
    my $icw_queue =  $icw_ticket->{'Queue'};
	$icw_ticket->{'Queue'} = $ticket_queues_map->{$icw_ticket->{'Queue'}};
    if ( $icw_ticket->{'Queue'} eq 'Obsolète' ) {
        $icw_ticket->{'CF.{File/Groupe ICW}'} = $icw_queue;
    }
	# CustomFields are handled after creation/update
	my $customfields;
	foreach my $key (keys %{$icw_ticket}) {
		if ( $key =~ m/^CF\.{(.*)}$/i ) {
			my $customfield = $1;
			my $value = delete ($icw_ticket->{$key});
            $value =~ s/\r//g if ( $value);
			if ( $customfield =~ m/^Type\/Catégorie\/Domaine\/Sous-domaine$/ ) {
				# $value shoud be /Type/Catégorie/Domaine/Sous-domaine/
				$value =~ s/^\///;
				$value =~ s/\/$//;
				my ($type, $category, $domain, $subdomain) = split /\//, $value;
				$customfields->{'Type'} = $type if ( $type );
				$customfields->{'Catégorie'} = $category if ( $category );
				$customfields->{'Domaine'} = $domain if ( $domain );
				$customfields->{'Sous-domaine'} = $subdomain if ( $subdomain );
			} else {
				$customfields->{$customfield} = $value;
			}
		}
	}
	$customfields->{'Numéro de ticket ICW'} = $icw_id;

	my $rt_ticket = RT::Ticket->new( RT->SystemUser );
	#my $rt_tickets = RT::Tickets->new( RT->SystemUser );
	#$rt_tickets->LimitCustomField( CUSTOMFIELD => $ticket_customfields->{'Numéro de ticket ICW'}->{id}, VALUE => $icw_id );

	#unless ( $rt_tickets->Count ) {
		RT->Logger->debug("Adding ticket ".$icw_id);
		my ($rt_id, $rt_trans, $rt_msg) = $rt_ticket->Create(
			Queue => $icw_ticket->{Queue},
			Subject => $icw_ticket->{Subject},
			Status => $icw_ticket->{Status},
			Due => $icw_ticket->{Due},
			Resolved => $icw_ticket->{Resolved},
			_RecordTransaction => 0,
		);
		unless ( $rt_id ) {
			RT->Logger->crit("Unable to add ticket ".$icw_id." to queue ".$icw_ticket->{Queue}.": $rt_msg");
			next;
		} else {
			delete $icw_ticket->{Queue};
			delete $icw_ticket->{Subject};
			delete $icw_ticket->{Status};
			delete $icw_ticket->{Due};
			delete $icw_ticket->{Resolved};
		}
	#} else {
	#	$rt_ticket = $rt_tickets->First;
	#}
	$tickets_map->{$icw_id} = $rt_ticket->id;
	RT->Logger->debug("Updating ticket with icw id: ".$icw_id.", rt id: ".$rt_ticket->id );
	foreach my $attr ( keys %{$icw_ticket} ) {
		next unless ( $icw_ticket->{$attr} );
		# Update LastUpdated at this end ...
		next if ( $attr eq 'LastUpdated' );
		my $current_value;
		if ( $attr eq 'Queue' ) {
			$current_value = $rt_ticket->QueueObj->Name;
		} elsif ( $attr eq 'RefersTo' ) {
			my $Asset = RT::Asset->new( RT->SystemUser );
			$Asset->Load( $icw_ticket->{RefersTo} );
			my $Links = RT::Links->new( RT->SystemUser );
			$Links->Limit( FIELD => 'Base', VALUE => $rt_ticket->URI );
			$Links->Limit( FIELD => 'Target', VALUE => $Asset->URI );
			$Links->Limit( FIELD => 'Type', VALUE => 'RefersTo' );
			next if ( $Links->Count );
			$icw_ticket->{$attr} = $Asset->URI;
		} else {
			$current_value = $rt_ticket->$attr;
		}

		if ( $current_value && ref($current_value eq 'ARRAY') ) {
			next if ( grep { $_ eq $icw_ticket->{$attr} } @{$current_value} );
		} elsif ( $current_value ) {
			next if ( $current_value eq $icw_ticket->{$attr} );
		}
		if ( $attr eq 'Requestor' || $attr eq 'Owner' ) {
			my $role_group = $rt_ticket->RoleGroup($attr);
			#unless ( $role_group->HasMember($icw_ticket->{$attr}) ) {
				# No acls checks because old owners may not have right to own tickets on this queue
				($val, $msg) = $role_group->_AddMember(
					PrincipalId => $icw_ticket->{$attr},
					InsideTransaction => 1,
					RecordTransaction => 0,
					Object => $rt_ticket, );
			#}
		} elsif ( $attr eq 'RefersTo' ) {
			($val, $msg) = $rt_ticket->AddLink(Type => 'RefersTo', Target => $icw_ticket->{RefersTo}, Silent => 1);
		} else {
			# Use __Set for immutable fields
			if ( $attr eq 'Created' ) {
				($val, $msg) = $rt_ticket->__Set( Field => $attr, Value => $icw_ticket->{$attr} );
			} else {
				my $method = 'Set'.$attr;
				($val, $msg) = $rt_ticket->$method( $icw_ticket->{$attr} );
			}
		}
		unless ( $val ) {
			RT->Logger->warning("Unable to update attribute $attr for ticket ".$rt_ticket->id.": $msg");
		}
	}

	foreach my $cf_name (keys %{$customfields}) {
		my $value = $customfields->{$cf_name};
		next unless ( $value );
                $value =~ s/\r//g;
		my $category = undef;
		if ( $tickets_parents->{$cf_name} ) {
			$category = $customfields->{$tickets_parents->{$cf_name}};
		}
	
		if ( $ticket_customfields->{$cf_name}->{Type} eq 'Select' ) {
			push @{$ticket_customfields->{$cf_name}->{Values}}, { Name => $value, Category => $category } unless ( grep { $_->{Name} eq $value } @{$ticket_customfields->{$cf_name}->{Values}} );
		}

		#my $current_value = $rt_ticket->FirstCustomFieldValue( $ticket_customfields->{$cf_name}->{id} );
		#next if ( $current_value && $value && $current_value eq $value );
	
		($val, $msg) = $rt_ticket->AddCustomFieldValue( Field => $ticket_customfields->{$cf_name}->{id}, Value => $value, RecordTransaction => 0 );
		unless ( $val ) {
			RT->Logger->warning("Unable to set value of customfield $cf_name for ticket ".$rt_ticket->id.": $msg");
		}
	}

	# Adding comments
	$ticket_comments_sth->execute($icw_id);
	RT->Logger->debug("Found ".$ticket_comments_sth->rows." comment(s)");
	# FIXME check current comments count and skip if it's the same. Add N newers ordered by id if > ?
	while ( my $icw_comment = $ticket_comments_sth->fetchrow_hashref('NAME')) {
		RT->Logger->debug("Adding comment");
		$icw_comment->{Content} =~ s/\r//g;
		my ($comment_trans_id, $comment_msg, $comment_trans) = $rt_ticket->Comment(
			Content => $icw_comment->{Content},
			CommitScrips => 0,
		);
		unless ( $comment_trans_id ) {
			RT->Logger->warning("Unable to add comment to ticket ".$rt_ticket->id.": $comment_msg");
		} else {
			$comment_trans->__Set(Field => 'Created', Value => $icw_comment->{Created} );
			my $attachment = $comment_trans->Attachments->First;
			$attachment->__Set(Field => 'Created', Value => $icw_comment->{Created} );
		}
	}
	# Finally update LastUpdated date
	$rt_ticket->__Set( Field => 'LastUpdated', Value => $icw_ticket->{'LastUpdated'} );
}
$tickets_sth->finish();
$ticket_comments_sth->finish();

# Update ticket customfields values

foreach my $cf_name ( keys %{$ticket_customfields} ) {
	next unless ( $ticket_customfields->{$cf_name}->{Type} eq 'Select' );
	next unless ( $ticket_customfields->{$cf_name}->{Values} );
	next unless ( scalar @{$ticket_customfields->{$cf_name}->{Values}} );

	my $CustomField = RT::CustomField->new( RT->SystemUser );
	$CustomField->Load($ticket_customfields->{$cf_name}->{id});
	my $Values = $CustomField->Values;
	while (my $Value = $Values->Next) {
		$Value->Delete;
	}
	foreach my $value (@{$ticket_customfields->{$cf_name}->{Values}}) {
		$CustomField->AddValue( %{$value} );
	}
}


my $end_time = time;
my $elapsed = $end_time - $start_time;

RT->Logger->crit("Elapsed: $elapsed seconds");
