package domain

import (
	"net"

	"github.com/transip/gotransip/v6/rest"
)

// PerformAction List of available actions to perform on this domain.
// Possible actions are: 'register', 'transfer', 'internalpull' and 'internalpush'
type PerformAction string

// define all possible actions that a user can perform on a domain
const (
	// PerformActionTransfer is the available perform transfer action
	PerformActionTransfer PerformAction = "transfer"
	// PerformActionInternalPull is the available perform internalpull action,
	// for when a domain is at transip and can be handovered pushed/pulled towards a different account
	PerformActionInternalPull PerformAction = "internalpull"
	// PerformActionInternalPush is the available perform internalpush action,
	// for when a domain is at transip and can be handovered pushed/pulled towards a different account
	PerformActionInternalPush PerformAction = "internalpush"
)

// AvailabilityStatus is the status for a domain. Returned during queries upon the availability
// Possible statuses are: 'inyouraccount', 'unavailable', 'notfree', 'free', 'internalpull', 'internalpush'
type AvailabilityStatus string

// define all possible availability statuses
const (
	// AvailabilityStatusInYourAccount is the availability status for when a domain is already in your account
	AvailabilityStatusInyouraccount AvailabilityStatus = "inyouraccount"
	// AvailabilityStatusUnavailable is the availability status for when a domain is unavailable
	AvailabilityStatusUnavailable AvailabilityStatus = "unavailable"
	// AvailabilityStatusNotFree is the availability status for when a domain is already taken
	AvailabilityStatusNotFree AvailabilityStatus = "notfree"
	// AvailabilityStatusFree is the availability status for when a domain is free to register
	AvailabilityStatusFree AvailabilityStatus = "free"
	// AvailabilityStatusInternalPull is the availability status,
	// for when a domain is at transip and can be handovered pushed/pulled towards a different account
	AvailabilityStatusInternalPull AvailabilityStatus = "internalpull"
	// AvailabilityStatusInternalPush is the availability status,
	// for when a domain is at transip and can be handovered pushed/pulled towards a different account
	AvailabilityStatusInternalPush AvailabilityStatus = "internalpush"
)

// domainsResponse struct contains a list of Domains in it,
// this is solely used for unmarshalling/marshalling
type domainsResponse struct {
	Domains []Domain `json:"domains"`
}

// domainWrapper struct contains a Domain in it,
// this is solely used for unmarshalling/marshalling
type domainWrapper struct {
	Domain Domain `json:"domain"`
}

// domainBrandingWrapper struct contains a Branding struct in it,
// this is solely used for unmarshalling/marshalling
type domainBrandingWrapper struct {
	Branding Branding `json:"branding"`
}

// dnsEntriesWrapper struct contains a DNSEntry list in it,
// this is solely used for unmarshalling/marshalling
type dnsEntriesWrapper struct {
	DNSEntries []DNSEntry `json:"dnsEntries"`
}

// dnsEntryWrapper struct contains a DNSEntry struct in it,
// this is solely used for unmarshalling/marshalling
type dnsEntryWrapper struct {
	DNSEntry DNSEntry `json:"dnsEntry"`
}

// contactsWrapper struct contains a list of Contacts in it,
// this is solely used for unmarshalling/marshalling
type contactsWrapper struct {
	Contacts []WhoisContact `json:"contacts"`
}

// dnsSecEntriesWrapper struct contains a list of DNSSecEntry in it,
// this is solely used for unmarshalling/marshalling
type dnsSecEntriesWrapper struct {
	// All DNSSEC entries for a domain
	DNSSecEntries []DNSSecEntry `json:"dnsSecEntries"`
}

// nameserversWrapper struct contains a list of Nameservers in it,
// this is solely used for unmarshalling/marshalling
type nameserversWrapper struct {
	Nameservers []Nameserver `json:"nameservers"`
}

// actionWrapper struct contains a Action in it, this is solely used for unmarshalling/marshalling
type actionWrapper struct {
	Action Action `json:"action"`
}

// retryActionWrapper object is used to create a retry action request body
type retryActionWrapper struct {
	// The authcode for this domain as generated by the registry.
	AuthCode string `json:"authCode,omitempty"`
	// Optionally you can set different domain dns entries
	DNSEntries []DNSEntry `json:"dnsEntries,omitempty"`
	// Optionally you can set different nameservers
	Nameservers []Nameserver `json:"nameservers,omitempty"`
	// Optionally you can set different whois contacts
	Contacts []WhoisContact `json:"contacts"`
}

// certificatesWrapper struct contains a list of SslCertificates in it,
// this is solely used for unmarshalling
type certificatesWrapper struct {
	Certificates []SslCertificate `json:"certificates"`
}

// certificateWrapper struct contains a SslCertificate in it,
// this is solely used for unmarshalling
type certificateWrapper struct {
	Certificate SslCertificate `json:"certificate"`
}

// whoisWrapper struct contains a whois string in it,
// this is solely used for unmarshalling
type whoisWrapper struct {
	Whois string `json:"whois"`
}

// availabilityWrapper struct contains a Availability struct in it,
// this is solely used for unmarshalling
type availabilityWrapper struct {
	Availability Availability `json:"availability"`
}

// availabilityListWrapper struct contains a list of Availability structs in it,
// this is solely used for unmarshalling
type availabilityListWrapper struct {
	AvailabilityList []Availability `json:"availability"`
}

// this struct is used to generate a json request
// for the multiple domain names availability option
type multipleAvailabilityRequest struct {
	DomainNames []string `json:"domainNames"`
}

// tldsWrapper struct contains a list of Tlds in it,
// this is solely used for unmarshalling
type tldsWrapper struct {
	Tlds []Tld `json:"tlds"`
}

// tldWrapper struct contains a list of Tld in it,
// this is solely used for unmarshalling
type tldWrapper struct {
	Tld Tld `json:"tld"`
}

// Contact struct for a Contact
type Contact struct {
	// Email address of the contact
	Email string `json:"email"`
	// ID number of the contact
	ID int64 `json:"id"`
	// Name of the contact
	Name string `json:"name"`
	// Telephone number of the contact
	Telephone string `json:"telephone"`
}

// DNSEntry struct for a DNSEntry
type DNSEntry struct {
	// The name of the dns entry, for example '@' or 'www'
	Name string `json:"name"`
	// The expiration period of the dns entry, in seconds. For example 86400 for a day of expiration
	Expire int `json:"expire"`
	// The type of dns entry. Possbible types are 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SRV', 'SSHFP' and 'TLSA'
	Type string `json:"type"`
	// The content of of the dns entry, for example '10 mail', '127.0.0.1' or 'www'
	Content string `json:"content"`
}

// WhoisContact struct for a whois contact
type WhoisContact struct {
	// The type of this Contact, 'registrant', 'administrative' or 'technical'
	Type string `json:"type"`
	// The firstName of this Contact
	FirstName string `json:"firstName"`
	// The lastName of this Contact
	LastName string `json:"lastName"`
	// The companyName of this Contact, in case of a company
	CompanyName string `json:"companyName"`
	// The kvk number of this Contact, in case of a company
	CompanyKvk string `json:"companyKvk"`
	// The type number of this Contact, in case of a company.
	// Possible types are: 'BV', 'BVI/O', 'COOP', 'CV', 'EENMANSZAAK', 'KERK', 'NV',
	// 'OWM', 'REDR', 'STICHTING', 'VERENIGING', 'VOF', 'BEG', 'BRO', 'EESV' and 'ANDERS'
	CompanyType string `json:"companyType"`
	// The street of the address of this Contact
	Street string `json:"street"`
	// The number part of the address of this Contact
	Number string `json:"number"`
	// The postalCode part of the address of this Contact
	PostalCode string `json:"postalCode"`
	// The city part of the address of this Contact
	City string `json:"city"`
	// The phoneNumber of this Contact
	PhoneNumber string `json:"phoneNumber"`
	// The faxNumber of this Contact
	FaxNumber string `json:"faxNumber,omitempty"`
	// The email address of this Contact
	Email string `json:"email"`
	// The country of this Contact, one of the ISO 3166-1 2 letter country codes, must be lowercase.
	Country string `json:"country"`
}

// Action struct for a domain Action
type Action struct {
	// If this action has failed, this field will be true.
	HasFailed bool `json:"hasFailed,omitempty"`
	// If this action has failed, this field will contain an descriptive message.
	Message string `json:"message,omitempty"`
	// The name of this Action.
	Name string `json:"name"`
}

// SslCertificate struct for a SslCertificate
type SslCertificate struct {
	// The id of the certificate, can be used to retrieve additional info
	CertificateID int `json:"certificateId"`
	// The domain name that the SSL certificate is added to. Start with '*.' when the certificate is a wildcard.
	CommonName string `json:"commonName"`
	// Expiration date
	ExpirationDate string `json:"expirationDate"`
	// The current status, either 'active', 'inactive' or 'expired'
	Status string `json:"status"`
}

// Domain struct for a Domain
type Domain struct {
	// The custom tags added to this domain.
	Tags []string `json:"tags"`
	// The authcode for this domain as generated by the registry.
	AuthCode string `json:"authCode,omitempty"`
	// Cancellation data, in YYYY-mm-dd h:i:s format, null if the domain is active.
	CancellationDate rest.Time `json:"cancellationDate,omitempty"`
	// Cancellation status, null if the domain is active, 'cancelled' when the domain is cancelled.
	CancellationStatus string `json:"cancellationStatus,omitempty"`
	// Whether this domain is DNS only
	IsDNSOnly bool `json:"isDnsOnly,omitempty"`
	// If this domain supports transfer locking, this flag is true when the domains ability to transfer is locked at the registry.
	IsTransferLocked bool `json:"isTransferLocked"`
	// If this domain is added to your whitelabel.
	IsWhitelabel bool `json:"isWhitelabel"`
	// The name, including the tld of this domain
	Name string `json:"name"`
	// Registration date of the domain, in YYYY-mm-dd format.
	RegistrationDate rest.Date `json:"registrationDate,omitempty"`
	// Next renewal date of the domain, in YYYY-mm-dd format.
	RenewalDate rest.Date `json:"renewalDate,omitempty"`
	// Status of the domain
	Status string `json:"status,omitempty"`
}

// Branding struct for a Branding, this information is shown in the whois information
type Branding struct {
	// The first generic bannerLine displayed in whois-branded whois output.
	BannerLine1 string `json:"bannerLine1"`
	// The second generic bannerLine displayed in whois-branded whois output.
	BannerLine2 string `json:"bannerLine2"`
	// The third generic bannerLine displayed in whois-branded whois output.
	BannerLine3 string `json:"bannerLine3"`
	// The company name displayed in transfer-branded e-mails
	CompanyName string `json:"companyName"`
	// The company url displayed in transfer-branded e-mails
	CompanyURL string `json:"companyUrl"`
	// The support email used for transfer-branded e-mails
	SupportEmail string `json:"supportEmail"`
	// The terms of usage url as displayed in transfer-branded e-mails
	TermsOfUsageURL string `json:"termsOfUsageUrl"`
}

// DNSSecEntry struct for a DNSSecEntry
type DNSSecEntry struct {
	// The algorithm type that is used,
	// see: https://www.transip.nl/vragen/461-domeinnaam-nameservers-gebruikt-beveiligen-dnssec/ for the possible options.
	Algorithm int `json:"algorithm"`
	// The signing key number, either 256 (Zone Signing Key) or 257 (Key Signing Key)
	Flags int `json:"flags"`
	// A 5-digit key of the Zonesigner
	KeyTag int `json:"keyTag"`
	// The public key
	PublicKey string `json:"publicKey"`
}

// Tld struct for a Tld
type Tld struct {
	// Number of days a domain needs to be canceled before the renewal date.
	CancelTimeFrame int `json:"cancelTimeFrame,omitempty"`
	// A list of the capabilities that this Tld has (the things that can be done with a domain under this tld).
	// Possible capabilities are: 'requiresAuthCode', 'canRegister', 'canTransferWithOwnerChange',
	// 'canTransferWithoutOwnerChange', 'canSetLock', 'canSetOwner', 'canSetContacts', 'canSetNameservers',
	// 'supportsDnsSec'
	Capabilities []string `json:"capabilities,omitempty"`
	// The maximum amount of characters need for registering a domain under this TLD.
	MaxLength int `json:"maxLength,omitempty"`
	// The minimum amount of characters need for registering a domain under this TLD.
	MinLength int `json:"minLength,omitempty"`
	// The name of this TLD, including the starting dot. E.g. .nl or .com.
	Name string `json:"name"`
	// Price of the TLD in cents
	Price int `json:"price,omitempty"`
	// Price for renewing the TLD in cents
	RecurringPrice int `json:"recurringPrice,omitempty"`
	// Length in months of each registration or renewal period.
	RegistrationPeriodLength int `json:"registrationPeriodLength,omitempty"`
}

// Availability struct for an Availability
type Availability struct {
	// List of available actions to perform on this domain. Possible actions are: 'register', 'transfer', 'internalpull' and 'internalpush'
	Actions []PerformAction `json:"actions"`
	// The name of the domain
	DomainName string `json:"domainName"`
	// The status for this domain. Possible statuses are: 'inyouraccount', 'unavailable', 'notfree', 'free', 'internalpull' and 'internalpush'
	Status AvailabilityStatus `json:"status"`
}

// Nameserver struct for a Nameserver
type Nameserver struct {
	// The hostname of this nameserver
	Hostname string `json:"hostname"`
	// Optional ipv4 glue record for this nameserver
	IPv4 net.IP `json:"ipv4,omitempty"`
	// Optional ipv6 glue record for this nameserver
	IPv6 net.IP `json:"ipv6,omitempty"`
}

// Register struct used when registering a new domain
type Register struct {
	// The name, including the tld of the domain
	DomainName string `json:"domainName"`
	// Optionally you can set whois contacts
	Contacts []Contact `json:"contacts,omitempty"`
	// Optionally you can set the domain dns entries before transferring
	DNSEntries []DNSEntry `json:"dnsEntries,omitempty"`
	// Optionally you can set the domain nameservers before transferring
	Nameservers []Nameserver `json:"nameservers,omitempty"`
}

// Transfer struct used when transferring a domain to transip
type Transfer struct {
	// The name, including the tld of the domain
	DomainName string `json:"domainName"`
	// The authcode for this domain as generated by the registry.
	AuthCode string `json:"authCode"`
	// Optionally you can set whois contacts
	Contacts []Contact `json:"contacts,omitempty"`
	// Optionally you can set the domain dns entries before transferring
	DNSEntries []DNSEntry `json:"dnsEntries,omitempty"`
	// Optionally you can set the domain nameservers before transferring
	Nameservers []Nameserver `json:"nameservers,omitempty"`
}
