package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"strings"

	"recup_info_zimbra/pkg/ldap"
	"recup_info_zimbra/pkg/zimbra"
	"recup_info_zimbra/pkg/zxsuite"
)

const (
	BindUsername = "uid=zimbra,cn=admins,cn=zimbra"
	PathZimbra   = "/opt/zimbra"
	BaseDN       = "uid=zimbra,cn=admins,cn=zimbra"
)

type TemplateJsonInfluxDaily struct {
	FluxZimbra struct {
		FluxZimbraStore   TypeFluxZimbraVersion `json:"flux_zimbra_store"`
		FluxZimbraZextras TypeResponse          `json:"flux_zimbra_zextras"`
	} `json:"flux_zimbra"`
}

type TemplateJsonInfluxHourly struct {
	FluxZimbra struct {
		FluxZimbraLdap  TypeFluxZimbraLdap  `json:"flux_zimbra_ldap"`
		FluxZimbraProxy TypeFluxZimbraProxy `json:"flux_zimbra_proxy"`
		FluxZimbraMta   TypeFluxZimbraMta   `json:"flux_zimbra_mta"`
		FluxZimbraStore TypeFluxZimbraStore `json:"flux_zimbra_store"`
	} `json:"flux_zimbra"`
}

// STRUCT LDAP
type TypeFluxZimbraLdap struct {
	NumberCos         int    `json:"number_cos"`
	NumberDomain      int    `json:"number_domain"`
	NumberAliasDomain int    `json:"number_alias_domain"`
	NumberLdapServer  int    `json:"number_ldap_server"`
	NameLdapServer    string `json:"name_ldap_server"`
}

// STRUCT PROXY
type TypeFluxZimbraProxy struct {
	NumberProxyServer int    `json:"number_proxy_server"`
	NameProxyServer   string `json:"name_proxy_server"`
}

// STRUCT MTA
type TypeFluxZimbraMta struct {
	NumberMtaServer int    `json:"number_mta_server"`
	NameMtaServer   string `json:"name_mta_server"`
}

// STRUCT STORE
type TypeFluxZimbraStore struct {
	NumberDl                 int    `json:"number_dl"`
	NumberAccount            int    `json:"number_account"`
	NumberAdminAccount       int    `json:"number_admin_account"`
	NumberResourceEquipment  int    `json:"number_resource_equipment"`
	NumberResourceLocation   int    `json:"number_resource_location"`
	NumberActiveAccount      int    `json:"number_active_account"`
	NumberMaintenanceAccount int    `json:"number_maintenance_account"`
	NumberLockedAccount      int    `json:"number_locked_account"`
	NumberClosedAccount      int    `json:"number_closed_account"`
	NumberLockoutAccount     int    `json:"number_lockout_account"`
	NumberPendingAccount     int    `json:"number_pending_account"`
	NumberStoreServer        int    `json:"number_store_server"`
	NameStoreServer          string `json:"name_store_server"`
}

type TypeFluxZimbraVersion struct {
	System  string `json:"system"`
	Version string `json:"version"`
	Edition string `json:"edition"`
	Patch   string `json:"patch"`
}
type TypeResponse struct {
	ZextrasVersion        string `json:"zextras_version"`
	ZextrasCommit         string `json:"zextras_commit"`
	ZalVersion            string `json:"zal_version"`
	ZalCommit             string `json:"zal_commit"`
	DateStart             int64  `json:"dateStart"`
	DateEnd               int64  `json:"dateEnd"`
	Expired               bool   `json:"expired"`
	Type                  string `json:"type"`
	Customer              string `json:"customer"`
	Reseller              string `json:"reseller"`
	Company               string `json:"company"`
	OrderID               string `json:"order_id"`
	AccountCount          int    `json:"accountCount"`
	LicensedUsers         string `json:"licensedUsers"`
	NotYetValid           bool   `json:"notYetValid"`
	IsWithinGraceInterval bool   `json:"isWithinGraceInterval"`
	TeamchatActiveCount   int    `json:"teamchatActiveCount"`
	TeamchatBasicActive   bool   `json:"teamchatBasicActive"`
	Modules               struct {
		ZxBackup struct {
			Quantity string `json:"quantity"`
			Licensed bool   `json:"licensed"`
		} `json:"ZxBackup"`
		ZxMobile struct {
			Quantity string `json:"quantity"`
			Licensed bool   `json:"licensed"`
		} `json:"ZxMobile"`
		ZxAdmin struct {
			Quantity string `json:"quantity"`
			Licensed bool   `json:"licensed"`
		} `json:"ZxAdmin"`
		ZxPowerstore struct {
			Quantity    string `json:"quantity"`
			Licensed    bool   `json:"licensed"`
			EnabledOnNE bool   `json:"enabledOnNE"`
		} `json:"ZxPowerstore"`
		SproxyD struct {
			Quantity    string `json:"quantity"`
			Licensed    bool   `json:"licensed"`
			EnabledOnNE bool   `json:"enabledOnNE"`
		} `json:"SproxyD"`
		ZxDrive struct {
			Quantity string `json:"quantity"`
			Licensed bool   `json:"licensed"`
		} `json:"ZxDrive"`
		ZxDocs struct {
			Quantity string `json:"quantity"`
			Licensed bool   `json:"licensed"`
		} `json:"ZxDocs"`
		ZxChat struct {
			Quantity string `json:"quantity"`
			Licensed bool   `json:"licensed"`
		} `json:"ZxChat"`
		ZxHA struct {
			Quantity string `json:"quantity"`
			Licensed bool   `json:"licensed"`
		} `json:"ZxHA"`
	} `json:"modules"`
	ServerID           string `json:"serverID"`
	CanRemoveChatBrand bool   `json:"canRemoveChatBrand"`

	Exists                    bool `json:"exists"`
	Readable                  bool `json:"readable"`
	Valid                     bool `json:"valid"`
	Empty                     bool `json:"empty"`
	Lockok                    bool `json:"lockok"`
	Writable                  bool `json:"writable"`
	AvailableSpaceForBlobs    int  `json:"availableSpaceForBlobs"`
	AvailableSpaceForMetadata int  `json:"availableSpaceForMetadata"`
	CaseSensitive             bool `json:"caseSensitive"`
	BackupStat                struct {
		Scan struct {
			FirstScan                 int    `json:"firstScan"`
			FirstZeXtrasBuild         string `json:"firstZeXtrasBuild"`
			FirstZimbraVersion        string `json:"firstZimbraVersion"`
			NumNewAccounts            int    `json:"numNewAccounts"`
			NumBackupedItems          int    `json:"numBackupedItems"`
			NumSkippedAccounts        int    `json:"numSkippedAccounts"`
			NumCheckedItems           int    `json:"numCheckedItems"`
			FirstZeXtrasVersion       string `json:"firstZeXtrasVersion"`
			LastZimbraVersion         string `json:"lastZimbraVersion"`
			NumActiveBackupedAccounts int    `json:"numActiveBackupedAccounts"`
			NumContentFiles           int    `json:"numContentFiles"`
			NumUpAccounts             int    `json:"numUpAccounts"`
			LastScan                  int    `json:"lastScan"`
			LastZeXtrasBuild          string `json:"lastZeXtrasBuild"`
			NumNewItems               int    `json:"numNewItems"`
			LastDeepScan              int    `json:"lastDeepScan"`
			NumDeletedAccounts        int    `json:"numDeletedAccounts"`
			NumCheckedAccounts        int    `json:"numCheckedAccounts"`
			ItemsPerSecond            int    `json:"itemsPerSecond"`
			NumDeletedItems           int    `json:"numDeletedItems"`
			LastZeXtrasVersion        string `json:"lastZeXtrasVersion"`
			NumUpItems                int    `json:"numUpItems"`
		} `json:"scan"`
		Purge struct {
			NumTotalAccounts    int `json:"numTotalAccounts"`
			NumPurgedItems      int `json:"numPurgedItems"`
			NumPurgedAccounts   int `json:"numPurgedAccounts"`
			NumCheckedItems     int `json:"numCheckedItems"`
			NumPurgedServerConf int `json:"numPurgedServerConf"`
			NumCheckedAccounts  int `json:"numCheckedAccounts"`
			ItemsPerSecond      int `json:"itemsPerSecond"`
			NumPurgedDigests    int `json:"numPurgedDigests"`
		} `json:"purge"`
	} `json:"backupStat"`
	DataPath string `json:"dataPath"`
}

type TemplateGetVersion struct {
	Ok       bool         `json:"ok"`
	Response TypeResponse `json:"response"`
}

func main() {

	error := zimbra.ReadLocalConfig(PathZimbra)
	if error != nil {
		log.Fatal(error)
	}
	FQDN, _ := zimbra.Get("zimbra_server_hostname")
	ldapHost, _ := zimbra.Get("ldap_host")
	BindPassword, _ := zimbra.Get("zimbra_ldap_password")

	var outputJsonDaily TemplateJsonInfluxDaily
	var outputJsonHourly TemplateJsonInfluxHourly
	SearchAccount := "(&(objectClass=zimbraAccount)(!(zimbraIsSystemAccount=TRUE))(!(zimbraIsSystemResource=TRUE))(zimbraMailHost=" + FQDN + ")"
	AccountFilter := SearchAccount + ")"
	SearchServer := "(&(objectClass=zimbraServer)(cn=" + FQDN + ")"

	typesearchldap := []ldap.TypesearchCount{
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraLdap.NumberCos,
			SearchLdap: "(&(objectClass=zimbraCos))",
			LdapAttrs:  []string{"cn"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraLdap.NumberDomain,
			SearchLdap: "(&(objectClass=zimbraDomain)(zimbraDomainType=local))",
			LdapAttrs:  []string{"zimbraDomainName"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraLdap.NumberAliasDomain,
			SearchLdap: "(&(objectClass=zimbraDomain)(zimbraDomainType=alias))",
			LdapAttrs:  []string{"zimbraDomainName"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraLdap.NumberLdapServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=ldap))",
			LdapAttrs:  []string{"cn"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraProxy.NumberProxyServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=proxy))",
			LdapAttrs:  []string{"cn"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraMta.NumberMtaServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=mta))",
			LdapAttrs:  []string{"cn"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberDl,
			SearchLdap: "(&(objectclass=zimbradistributionlist)(zimbramailhost=" + FQDN + "))",
			LdapAttrs:  []string{"zimbraMailAlias"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberAccount,
			SearchLdap: AccountFilter,
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberAdminAccount,
			SearchLdap: "(&(objectClass=zimbraAccount)(zimbraIsAdminAccount=TRUE)(zimbraMailHost=" + FQDN + "))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberResourceEquipment,
			SearchLdap: SearchAccount + "(zimbraCalResType=Equipment))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberResourceLocation,
			SearchLdap: SearchAccount + "(zimbraCalResType=Location))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberActiveAccount,
			SearchLdap: SearchAccount + "(zimbraAccountStatus=active))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberMaintenanceAccount,
			SearchLdap: SearchAccount + "(zimbraAccountStatus=maintenance))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberLockedAccount,
			SearchLdap: SearchAccount + "(zimbraAccountStatus=locked))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberClosedAccount,
			SearchLdap: SearchAccount + "(zimbraAccountStatus=closed))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberLockoutAccount,
			SearchLdap: SearchAccount + "(zimbraAccountStatus=lockout))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberPendingAccount,
			SearchLdap: SearchAccount + "(zimbraAccountStatus=pending))",
			LdapAttrs:  []string{"zimbraMailDeliveryAddress"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NumberStoreServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=mailbox))",
			LdapAttrs:  []string{"cn"}},
	}

	typesearchldapval := []ldap.TypesearchLdapValues{
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraLdap.NameLdapServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=ldap))",
			LdapAttrs:  []string{"cn"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraProxy.NameProxyServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=proxy))",
			LdapAttrs:  []string{"cn"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraMta.NameMtaServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=mta))",
			LdapAttrs:  []string{"cn"}},
		{
			ResultDest: &outputJsonHourly.FluxZimbra.FluxZimbraStore.NameStoreServer,
			SearchLdap: SearchServer + "(zimbraServiceEnabled=mailbox))",
			LdapAttrs:  []string{"cn"}},
	}
	// Non-TLS Connection
	l, err := ldap.Connect(ldapHost, BindUsername, BindPassword)
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()

	daily := flag.Bool("daily", false, "Daily excecution")
	hourly := flag.Bool("hourly", false, "Hourly excecution")

	flag.Parse()

	if *daily {
		outputZxVers, _ := zxsuite.CmdZxSuite("core", "getVersion")
		outputZxLicense, _ := zxsuite.CmdZxSuite("core", "getLicenseInfo")
		outputZxBackup, _ := zxsuite.CmdZxSuite("backup", "getBackupInfo")

		outputZmVers, _ := zxsuite.CmdZmcontrol("-v")
		rOut := strings.Split(strings.Replace(string(outputZmVers), "\n", "", -1), " ")

		version := strings.Split(string(rOut[6]), "_")
		patch := strings.Split(string(version[1]), ".")
		outputJsonDaily.FluxZimbra.FluxZimbraStore.System = rOut[2]
		outputJsonDaily.FluxZimbra.FluxZimbraStore.Version = version[0]
		outputJsonDaily.FluxZimbra.FluxZimbraStore.Edition = rOut[3]
		outputJsonDaily.FluxZimbra.FluxZimbraStore.Patch = patch[0]

		var templategetversion TemplateGetVersion

		json.Unmarshal([]byte(outputZxVers), &templategetversion)
		json.Unmarshal([]byte(outputZxLicense), &templategetversion)
		json.Unmarshal([]byte(outputZxBackup), &templategetversion)
		outputJsonDaily.FluxZimbra.FluxZimbraZextras = templategetversion.Response

		out, _ := json.Marshal(outputJsonDaily)
		fmt.Println(string(out))
	} else if *hourly {
		for _, s := range typesearchldap {
			ldap.SearchLdapCount(l, s)
		}
		for _, s := range typesearchldapval {
			ldap.SearchLdapVal(l, s, "cn")
		}
		out, _ := json.Marshal(outputJsonHourly)
		fmt.Println(string(out))
	} else {
		flag.Usage()
		os.Exit(1)
	}
}
