package scanmodel

import (
	"time"

	coremodel "security-center-backend/internal/model"
)

const (
	SourceAssetPlatform = "asset-platform"
)

type BatchStatus string

const (
	BatchStatusDraft      BatchStatus = "draft"
	BatchStatusSubmitting BatchStatus = "submitting"
	BatchStatusQueued     BatchStatus = "queued"
	BatchStatusRunning    BatchStatus = "running"
	BatchStatusCompleted  BatchStatus = "completed"
	BatchStatusFailed     BatchStatus = "failed"
	BatchStatusCanceled   BatchStatus = "canceled"
	BatchStatusSyncFailed BatchStatus = "sync_failed"
)

type CampaignStatus string

const (
	CampaignStatusQueued      CampaignStatus = "queued"
	CampaignStatusDispatching CampaignStatus = "dispatching"
	CampaignStatusRunning     CampaignStatus = "running"
	CampaignStatusCompleted   CampaignStatus = "completed"
	CampaignStatusFailed      CampaignStatus = "failed"
	CampaignStatusCanceled    CampaignStatus = "canceled"
	CampaignStatusSyncFailed  CampaignStatus = "sync_failed"
)

type TriggerType string

const (
	TriggerTypeManual TriggerType = "manual"
)

type TargetStatus string

const (
	TargetStatusPending     TargetStatus = "pending"
	TargetStatusAccepted    TargetStatus = "accepted"
	TargetStatusRejected    TargetStatus = "rejected"
	TargetStatusObserved    TargetStatus = "observed"
	TargetStatusSyncMissing TargetStatus = "sync_missing"
)

type ObservationResult string

const (
	ObservationResultConfirmedOpen   ObservationResult = "confirmed_open"
	ObservationResultConfirmedClosed ObservationResult = "confirmed_closed"
	ObservationResultUnknownFiltered ObservationResult = "unknown_or_filtered"
	ObservationResultSkipped         ObservationResult = "skipped"
)

type CallbackReceiptStatus string

const (
	CallbackReceiptStatusReceived  CallbackReceiptStatus = "received"
	CallbackReceiptStatusApplied   CallbackReceiptStatus = "applied"
	CallbackReceiptStatusDuplicate CallbackReceiptStatus = "duplicate"
	CallbackReceiptStatusConflict  CallbackReceiptStatus = "conflict"
	CallbackReceiptStatusInvalid   CallbackReceiptStatus = "invalid"
	CallbackReceiptStatusFailed    CallbackReceiptStatus = "failed"
)

type Batch struct {
	coremodel.Base
	RequestID         string            `gorm:"size:64;not null;uniqueIndex:uk_scan_batches_request_id" json:"request_id"`
	ScannerBatchID    *string           `gorm:"size:128;uniqueIndex:uk_scan_batches_scanner_batch_id" json:"scanner_batch_id,omitempty"`
	CampaignID        *uint64           `gorm:"index:idx_scan_batches_campaign;uniqueIndex:uk_scan_batches_campaign_part,priority:1" json:"campaign_id,omitempty"`
	Source            string            `gorm:"size:64;not null;default:asset-platform" json:"source"`
	Status            BatchStatus       `gorm:"size:32;not null;index:idx_scan_batches_status_created,priority:1" json:"status"`
	CreatedBy         *uint64           `gorm:"index:idx_scan_batches_created_by" json:"created_by,omitempty"`
	TriggerType       TriggerType       `gorm:"size:32;not null;default:manual" json:"trigger_type"`
	PartIndex         int               `gorm:"not null;default:0;uniqueIndex:uk_scan_batches_campaign_part,priority:2" json:"part_index"`
	PartCount         int               `gorm:"not null;default:1" json:"part_count"`
	TargetCount       int               `gorm:"not null;default:0" json:"target_count"`
	AcceptedTargets   int               `gorm:"not null;default:0" json:"accepted_targets"`
	RejectedTargets   int               `gorm:"not null;default:0" json:"rejected_targets"`
	QueuedJobs        int               `gorm:"not null;default:0" json:"queued_jobs"`
	RunningJobs       int               `gorm:"not null;default:0" json:"running_jobs"`
	SucceededJobs     int               `gorm:"not null;default:0" json:"succeeded_jobs"`
	FailedJobs        int               `gorm:"not null;default:0" json:"failed_jobs"`
	SkippedJobs       int               `gorm:"not null;default:0" json:"skipped_jobs"`
	SubmittedAt       *time.Time        `json:"submitted_at,omitempty"`
	CompletedAt       *time.Time        `json:"completed_at,omitempty"`
	LastSyncedAt      *time.Time        `json:"last_synced_at,omitempty"`
	ScannerError      *string           `gorm:"type:text" json:"scanner_error,omitempty"`
	RawCreateResponse coremodel.RawJSON `gorm:"type:json" json:"raw_create_response,omitempty"`
	Metadata          coremodel.JSONB   `gorm:"type:json" json:"metadata"`
	Campaign          *Campaign         `gorm:"foreignKey:CampaignID" json:"campaign,omitempty"`
	Targets           []Target          `gorm:"foreignKey:BatchID" json:"targets,omitempty"`
}

func (Batch) TableName() string {
	return "scan_batches"
}

type Campaign struct {
	coremodel.Base
	RequestID        string          `gorm:"size:64;not null;uniqueIndex:uk_scan_campaigns_request_id" json:"request_id"`
	Source           string          `gorm:"size:64;not null;default:caasm_ports" json:"source"`
	TargetScope      string          `gorm:"size:64;not null;default:all_public_ports" json:"target_scope"`
	Status           CampaignStatus  `gorm:"size:32;not null;index:idx_scan_campaigns_status_created,priority:1" json:"status"`
	CreatedBy        *uint64         `gorm:"index:idx_scan_campaigns_created_by" json:"created_by,omitempty"`
	TargetCount      int             `gorm:"not null;default:0" json:"target_count"`
	AcceptedTargets  int             `gorm:"not null;default:0" json:"accepted_targets"`
	RejectedTargets  int             `gorm:"not null;default:0" json:"rejected_targets"`
	QueuedJobs       int             `gorm:"not null;default:0" json:"queued_jobs"`
	RunningJobs      int             `gorm:"not null;default:0" json:"running_jobs"`
	SucceededJobs    int             `gorm:"not null;default:0" json:"succeeded_jobs"`
	FailedJobs       int             `gorm:"not null;default:0" json:"failed_jobs"`
	SkippedJobs      int             `gorm:"not null;default:0" json:"skipped_jobs"`
	BatchCount       int             `gorm:"not null;default:0" json:"batch_count"`
	CompletedBatches int             `gorm:"not null;default:0" json:"completed_batches"`
	FailedBatches    int             `gorm:"not null;default:0" json:"failed_batches"`
	NextCursor       uint64          `gorm:"not null;default:0" json:"next_cursor"`
	SubmittedAt      *time.Time      `json:"submitted_at,omitempty"`
	CompletedAt      *time.Time      `json:"completed_at,omitempty"`
	LastSyncedAt     *time.Time      `json:"last_synced_at,omitempty"`
	ScannerError     *string         `gorm:"type:text" json:"scanner_error,omitempty"`
	Metadata         coremodel.JSONB `gorm:"type:json" json:"metadata"`
	Batches          []Batch         `gorm:"foreignKey:CampaignID" json:"batches,omitempty"`
}

func (Campaign) TableName() string {
	return "scan_campaigns"
}

type Target struct {
	coremodel.Base
	BatchID         uint64            `gorm:"not null;uniqueIndex:uk_scan_targets_batch_endpoint,priority:1;index:idx_scan_targets_batch_status,priority:1" json:"batch_id"`
	CAASMAssetID    *uint64           `gorm:"index:idx_scan_targets_caasm_asset" json:"caasm_asset_id,omitempty"`
	CAASMIPAssetID  *uint64           `gorm:"index:idx_scan_targets_caasm_ip_asset" json:"caasm_ip_asset_id,omitempty"`
	CAASMPortID     *uint64           `gorm:"index:idx_scan_targets_caasm_port" json:"caasm_port_id,omitempty"`
	ScannerAssetID  string            `gorm:"size:64;not null" json:"scanner_asset_id"`
	ScannerTargetID *string           `gorm:"size:128;uniqueIndex:uk_scan_targets_scanner_target" json:"scanner_target_id,omitempty"`
	PublicIP        string            `gorm:"size:64;not null;uniqueIndex:uk_scan_targets_batch_endpoint,priority:2;index:idx_scan_targets_endpoint,priority:1" json:"public_ip"`
	Port            int               `gorm:"not null;uniqueIndex:uk_scan_targets_batch_endpoint,priority:3;index:idx_scan_targets_endpoint,priority:2" json:"port"`
	Transport       string            `gorm:"size:16;not null;default:tcp;uniqueIndex:uk_scan_targets_batch_endpoint,priority:4;index:idx_scan_targets_endpoint,priority:3" json:"transport"`
	Domain          *string           `gorm:"size:255" json:"domain,omitempty"`
	CloudProvider   *string           `gorm:"size:32" json:"cloud_provider,omitempty"`
	CloudAccountID  *string           `gorm:"size:64" json:"cloud_account_id,omitempty"`
	Region          *string           `gorm:"size:64" json:"region,omitempty"`
	ResourceType    *string           `gorm:"size:64" json:"resource_type,omitempty"`
	ResourceID      *string           `gorm:"size:255" json:"resource_id,omitempty"`
	Owner           *string           `gorm:"size:255" json:"owner,omitempty"`
	Environment     *string           `gorm:"size:64" json:"environment,omitempty"`
	AssetSnapshot   coremodel.RawJSON `gorm:"type:json" json:"asset_snapshot,omitempty"`
	PortSnapshot    coremodel.RawJSON `gorm:"type:json" json:"port_snapshot,omitempty"`
	TargetStatus    TargetStatus      `gorm:"size:32;not null;default:pending;index:idx_scan_targets_batch_status,priority:2" json:"target_status"`
	RejectReason    *string           `gorm:"size:64" json:"reject_reason,omitempty"`
	RejectDetail    *string           `gorm:"type:text" json:"reject_detail,omitempty"`
	Metadata        coremodel.JSONB   `gorm:"type:json" json:"metadata"`
	Batch           *Batch            `gorm:"foreignKey:BatchID" json:"batch,omitempty"`
}

func (Target) TableName() string {
	return "scan_targets"
}

type Observation struct {
	coremodel.Base
	BatchID              uint64            `gorm:"not null;uniqueIndex:uk_scan_observations_batch_job,priority:1;uniqueIndex:uk_scan_observations_batch_scanner_target,priority:1;uniqueIndex:uk_scan_observations_batch_endpoint,priority:1;index:idx_scan_observations_batch_result,priority:1" json:"batch_id"`
	TargetID             *uint64           `gorm:"index:idx_scan_observations_target" json:"target_id,omitempty"`
	ScannerObservationID *string           `gorm:"size:128;uniqueIndex:uk_scan_observations_scanner_observation" json:"scanner_observation_id,omitempty"`
	ScannerTargetID      *string           `gorm:"size:128;uniqueIndex:uk_scan_observations_batch_scanner_target,priority:2" json:"scanner_target_id,omitempty"`
	ScannerJobID         *string           `gorm:"size:128;uniqueIndex:uk_scan_observations_batch_job,priority:2" json:"scanner_job_id,omitempty"`
	CAASMAssetID         *uint64           `gorm:"index:idx_scan_observations_caasm_asset" json:"caasm_asset_id,omitempty"`
	CAASMPortID          *uint64           `gorm:"index:idx_scan_observations_caasm_port" json:"caasm_port_id,omitempty"`
	PublicIP             string            `gorm:"size:64;not null;uniqueIndex:uk_scan_observations_batch_endpoint,priority:2;index:idx_scan_observations_endpoint_observed,priority:1" json:"public_ip"`
	Port                 int               `gorm:"not null;uniqueIndex:uk_scan_observations_batch_endpoint,priority:3;index:idx_scan_observations_endpoint_observed,priority:2" json:"port"`
	Transport            string            `gorm:"size:16;not null;default:tcp;uniqueIndex:uk_scan_observations_batch_endpoint,priority:4;index:idx_scan_observations_endpoint_observed,priority:3" json:"transport"`
	Result               ObservationResult `gorm:"size:32;not null;index:idx_scan_observations_batch_result,priority:2" json:"result"`
	ReasonCode           string            `gorm:"size:64;not null" json:"reason_code"`
	ConnectMS            int64             `gorm:"not null;default:0" json:"connect_ms"`
	ScannerID            *string           `gorm:"size:128" json:"scanner_id,omitempty"`
	ScannerVersion       *string           `gorm:"size:64" json:"scanner_version,omitempty"`
	ScannerSourceIP      *string           `gorm:"size:64" json:"scanner_source_ip,omitempty"`
	EvidenceSHA256       *string           `gorm:"size:64" json:"evidence_sha256,omitempty"`
	EvidencePath         *string           `gorm:"size:1024" json:"evidence_path,omitempty"`
	StartedAt            *time.Time        `json:"started_at,omitempty"`
	FinishedAt           *time.Time        `json:"finished_at,omitempty"`
	ObservedAt           time.Time         `gorm:"not null;index:idx_scan_observations_endpoint_observed,priority:4" json:"observed_at"`
	RawPayload           coremodel.RawJSON `gorm:"type:json" json:"raw_payload,omitempty"`
	Metadata             coremodel.JSONB   `gorm:"type:json" json:"metadata"`
	Batch                *Batch            `gorm:"foreignKey:BatchID" json:"batch,omitempty"`
	Target               *Target           `gorm:"foreignKey:TargetID" json:"target,omitempty"`
}

func (Observation) TableName() string {
	return "scan_observations"
}

type CallbackReceipt struct {
	coremodel.Base
	IdempotencyKey      string                `gorm:"size:128;not null;uniqueIndex:uk_scan_callback_receipts_idempotency" json:"idempotency_key"`
	RequestID           *string               `gorm:"size:128" json:"request_id,omitempty"`
	ScannerBatchID      *string               `gorm:"size:128;index:idx_scan_callback_receipts_scanner_batch" json:"scanner_batch_id,omitempty"`
	LocalBatchID        *uint64               `gorm:"index:idx_scan_callback_receipts_batch" json:"local_batch_id,omitempty"`
	PayloadSHA256       string                `gorm:"size:64;not null" json:"payload_sha256"`
	HeaderPayloadSHA256 string                `gorm:"size:64;not null" json:"header_payload_sha256"`
	RequestHeaderID     *string               `gorm:"size:128" json:"request_header_id,omitempty"`
	Status              CallbackReceiptStatus `gorm:"size:32;not null;index:idx_scan_callback_receipts_status_received,priority:1" json:"status"`
	HTTPStatus          int                   `gorm:"not null" json:"http_status"`
	ErrorMessage        *string               `gorm:"type:text" json:"error_message,omitempty"`
	RawPayload          coremodel.RawJSON     `gorm:"type:json" json:"raw_payload,omitempty"`
	ReceivedAt          time.Time             `gorm:"not null;index:idx_scan_callback_receipts_status_received,priority:2" json:"received_at"`
	AppliedAt           *time.Time            `json:"applied_at,omitempty"`
	Metadata            coremodel.JSONB       `gorm:"type:json" json:"metadata"`
	LocalBatch          *Batch                `gorm:"foreignKey:LocalBatchID" json:"local_batch,omitempty"`
}

func (CallbackReceipt) TableName() string {
	return "scan_callback_receipts"
}
