package ofxgo

import (
	"errors"
	"fmt"
	"github.com/aclindsa/xml"
)

// SignonRequest identifies and authenticates a user to their FI and is
// provided with every Request
type SignonRequest struct {
	XMLName    xml.Name `xml:"SONRQ"`
	DtClient   Date     `xml:"DTCLIENT"` // Current time on client, overwritten in Client.Request()
	UserID     String   `xml:"USERID"`
	UserPass   String   `xml:"USERPASS,omitempty"`
	UserKey    String   `xml:"USERKEY,omitempty"`
	GenUserKey Boolean  `xml:"GENUSERKEY,omitempty"`
	Language   String   `xml:"LANGUAGE"` // Defaults to ENG
	Org        String   `xml:"FI>ORG"`
	Fid        String   `xml:"FI>FID"`
	AppID      String   `xml:"APPID"`  // Overwritten in Client.Request()
	AppVer     String   `xml:"APPVER"` // Overwritten in Client.Request()
	ClientUID  UID      `xml:"CLIENTUID,omitempty"`
}

// Name returns the name of the top-level transaction XML/SGML element
func (r *SignonRequest) Name() string {
	return "SONRQ"
}

// Valid returns (true, nil) if this struct would be valid OFX if marshalled
// into XML/SGML
func (r *SignonRequest) Valid(version ofxVersion) (bool, error) {
	if len(r.UserID) < 1 || len(r.UserID) > 32 {
		return false, errors.New("SONRQ>USERID invalid length")
	}
	if (len(r.UserPass) == 0) == (len(r.UserKey) == 0) {
		return false, errors.New("One and only one of SONRQ>USERPASS and USERKEY must be supplied")
	}
	if len(r.UserPass) > 32 {
		return false, errors.New("SONRQ>USERPASS invalid length")
	}
	if len(r.UserKey) > 64 {
		return false, errors.New("SONRQ>USERKEY invalid length")
	}
	if len(r.Language) == 0 {
		r.Language = "ENG"
	} else if len(r.Language) != 3 {
		return false, fmt.Errorf("SONRQ>LANGUAGE invalid length: \"%s\"", r.Language)
	}
	if len(r.AppID) < 1 || len(r.AppID) > 5 {
		return false, errors.New("SONRQ>APPID invalid length")
	}
	if len(r.AppVer) < 1 || len(r.AppVer) > 4 {
		return false, errors.New("SONRQ>APPVER invalid length")
	}
	return true, nil
}

// SignonResponse is provided with every Response and indicates the success or
// failure of the SignonRequest in the corresponding Request
type SignonResponse struct {
	XMLName     xml.Name `xml:"SONRS"`
	Status      Status   `xml:"STATUS"`
	DtServer    Date     `xml:"DTSERVER"`
	UserKey     String   `xml:"USERKEY,omitempty"`
	TsKeyExpire *Date    `xml:"TSKEYEXPIRE,omitempty"`
	Language    String   `xml:"LANGUAGE"`
	DtProfUp    *Date    `xml:"DTPROFUP,omitempty"`
	DtAcctUp    *Date    `xml:"DTACCTUP,omitempty"`
	Org         String   `xml:"FI>ORG"`
	Fid         String   `xml:"FI>FID"`
	SessCookie  String   `xml:"SESSCOOKIE,omitempty"`
	AccessKey   String   `xml:"ACCESSKEY,omitempty"`
}

// Name returns the name of the top-level transaction XML/SGML element
func (r *SignonResponse) Name() string {
	return "SONRS"
}

// Valid returns (true, nil) if this struct was valid OFX when unmarshalled
func (r *SignonResponse) Valid(version ofxVersion) (bool, error) {
	if len(r.Language) != 3 {
		return false, fmt.Errorf("SONRS>LANGUAGE invalid length: \"%s\"", r.Language)
	}
	return r.Status.Valid()
}
