<?php
namespace R2_Offload\Storage;

defined( 'ABSPATH' ) || exit;

/**
 * Static catalogue of supported storage providers.
 *
 * One place for: transport type, endpoint/url templates, the settings fields a
 * provider needs, public list pricing (for the cost estimator), step-by-step
 * signup/bucket guides, and pros/cons. No I/O here — pure data + tiny helpers.
 *
 * Pricing is public list price in USD, captured for estimation only. It is NOT
 * a quote; providers change prices and tiers. Sources noted per provider.
 */
final class Providers {

	/**
	 * @return array<string,array> keyed by provider id.
	 */
	public static function all(): array {
		return [
			'gcs'    => self::gcs(),
			's3'     => self::s3(),
			'r2'     => self::r2(),
			'b2'     => self::b2(),
			'wasabi' => self::wasabi(),
			'spaces' => self::spaces(),
			'bunny'  => self::bunny(),
		];
	}

	public static function get( string $id ): array {
		$all = self::all();
		return $all[ $id ] ?? $all['gcs'];
	}

	public static function exists( string $id ): bool {
		return array_key_exists( $id, self::all() );
	}

	/** Transport family: 'gcs' (SDK), 's3' (SigV4 HTTP), 'bunny' (HTTP). */
	public static function type( string $id ): string {
		return (string) ( self::get( $id )['type'] ?? 's3' );
	}

	public static function label( string $id ): string {
		return (string) ( self::get( $id )['label'] ?? $id );
	}

	private static function gcs(): array {
		return [
			'label'  => 'Google Cloud Storage',
			'type'   => 'gcs',
			'fields' => [ 'bucket', 'credentials_json', 'cdn_domain' ],
			'regions'=> [ 'us', 'eu', 'asia', 'us-central1', 'us-east1', 'europe-west1', 'asia-southeast1' ],
			'pricing'=> [
				// GCS Standard, regional. https://cloud.google.com/storage/pricing
				'storage_gb_month' => 0.020,
				'egress_gb'        => 0.12,
				'free_egress_gb'   => 0,
				'class_a_per_10k'  => 0.05,   // writes
				'class_b_per_10k'  => 0.004,  // reads
				'base_monthly'     => 0,
				'included_gb'      => 0,
				'min_storage_gb'   => 0,
				'min_storage_days' => 0,
			],
			'pros'   => [
				'Mature, highly durable (11 nines) global infrastructure.',
				'Tight integration with Google Cloud CDN and IAM.',
				'Strong tooling, lifecycle rules, object versioning.',
			],
			'cons'   => [
				'Internet egress is expensive ($0.12/GB) — costly for high-traffic media.',
				'Setup (service-account JSON, IAM) is the most involved of all providers.',
				'Per-operation charges add up on very large libraries.',
			],
			'guide'  => [
				'Open Google Cloud Console and create or select a project: https://console.cloud.google.com/projectcreate',
				'Enable the Cloud Storage API: https://console.cloud.google.com/apis/library/storage-component.googleapis.com',
				'Create a bucket (Storage → Buckets → Create). Pick a region near your visitors; Access control: Uniform.',
				'For public media: bucket → Permissions → Grant access → principal "allUsers" → role "Storage Object Viewer".',
				'IAM → Service Accounts → create one (e.g. "wp-media-offload").',
				'Bucket → Permissions → grant that service-account email role "Storage Object Admin" (scoped to this bucket).',
				'Service account → Keys → Add key → JSON → download.',
				'Paste the full JSON below, set Bucket to the bucket name, Save & Test.',
			],
		];
	}

	private static function s3(): array {
		return [
			'label'  => 'Amazon S3',
			'type'   => 's3',
			'fields' => [ 'bucket', 'region', 'access_key', 'secret_key', 'cdn_domain' ],
			'regions'=> [ 'us-east-1', 'us-east-2', 'us-west-1', 'us-west-2', 'eu-west-1', 'eu-central-1', 'eu-north-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1', 'ap-northeast-1', 'sa-east-1' ],
			'endpoint_tpl'   => 'https://s3.{region}.amazonaws.com',
			'public_url_tpl' => 'https://{bucket}.s3.{region}.amazonaws.com',
			'pricing'=> [
				// S3 Standard us-east-1. https://aws.amazon.com/s3/pricing/
				'storage_gb_month' => 0.023,
				'egress_gb'        => 0.09,
				'free_egress_gb'   => 100,   // 100 GB/mo free internet egress (AWS-wide)
				'class_a_per_10k'  => 0.05,  // PUT/COPY/POST/LIST
				'class_b_per_10k'  => 0.004, // GET/SELECT
				'base_monthly'     => 0,
				'included_gb'      => 0,
				'min_storage_gb'   => 0,
				'min_storage_days' => 0,
			],
			'pros'   => [
				'Industry standard; every tool and CDN integrates with it.',
				'CloudFront pairing gives cheap, global, low-latency delivery.',
				'Rich storage classes, lifecycle, replication, versioning.',
			],
			'cons'   => [
				'Direct egress ($0.09/GB) is pricey — you almost always need CloudFront.',
				'Request charges (PUT/GET) are billed; large libraries cost on writes.',
				'IAM policy + region nuances make first setup fiddly.',
			],
			'guide'  => [
				'Sign in to AWS Console → S3: https://s3.console.aws.amazon.com/s3/',
				'Create bucket → name it, choose a region near your visitors. Block Public Access OFF only if serving directly (prefer CloudFront).',
				'IAM → Users → create a user (programmatic access) with an inline policy granting s3:PutObject/GetObject/DeleteObject/ListBucket on this bucket and its objects.',
				'Create an access key for that user → copy Access Key ID + Secret Access Key.',
				'Below: set Bucket, Region (e.g. eu-central-1), paste Access Key + Secret. Save & Test.',
				'Optional but recommended: put CloudFront in front and set its domain as the CDN domain.',
			],
		];
	}

	private static function r2(): array {
		return [
			'label'  => 'Cloudflare R2',
			'type'   => 's3',
			'fields' => [ 'bucket', 'account_id', 'access_key', 'secret_key', 'cdn_domain' ],
			'regions'=> [ 'auto' ],
			'endpoint_tpl'   => 'https://{account_id}.r2.cloudflarestorage.com',
			'public_url_tpl' => '', // R2 has no public path-style URL; requires r2.dev or custom domain (CDN domain field).
			'pricing'=> [
				// https://developers.cloudflare.com/r2/pricing/
				'storage_gb_month' => 0.015,
				'egress_gb'        => 0.0,   // zero egress — the headline feature
				'free_egress_gb'   => 0,
				'class_a_per_10k'  => 0.045, // $4.50 / million writes
				'class_b_per_10k'  => 0.0036,// $0.36 / million reads
				'base_monthly'     => 0,
				'included_gb'      => 10,    // 10 GB storage free tier
				'min_storage_gb'   => 0,
				'min_storage_days' => 0,
				'egress_free'      => true,
			],
			'pros'   => [
				'Zero egress fees — by far the cheapest for high-traffic media.',
				'Generous free tier (10 GB storage, millions of ops/mo).',
				'S3-compatible API + Cloudflare CDN baked in.',
			],
			'cons'   => [
				'No public URL without a custom domain or the r2.dev managed domain (set it as CDN domain).',
				'region is always "auto"; needs the account-specific endpoint (account ID).',
				'Younger than S3/GCS; fewer third-party integrations.',
			],
			'guide'  => [
				'Cloudflare dashboard → R2 Object Storage → Overview. If this is your first time, enable R2 (a payment method is required even on the free tier).',
				'Create a bucket: "Create bucket" → name it → pick a location hint. After creating, open R2 → Overview and copy your Account ID (it is also the first part of the S3 endpoint https://<ACCOUNT_ID>.r2.cloudflarestorage.com).',
				'Create credentials: R2 → "Manage R2 API Tokens" (or "API" tab) → "Create API Token".',
				'Token type: choose "Account API Token" (NOT a User API Token). An Account token belongs to the account and keeps working for automation; a User token is tied to your personal login and breaks if your access changes.',
				'Permissions: pick "Object Read & Write" (enough to upload/serve/delete). Use "Admin Read & Write" only if you want the plugin to manage buckets. Scope it to this one bucket (least privilege) and leave TTL empty for a permanent integration.',
				'Click "Create API Token". Cloudflare shows the Access Key ID and Secret Access Key ONCE — copy both now (the Secret is not shown again).',
				'Make the bucket publicly reachable: open the bucket → Settings → Public access. For production connect a Custom Domain (recommended); the r2.dev managed subdomain is rate-limited and meant for development only. Copy that hostname.',
				'In the plugin below: Bucket = bucket name, Cloudflare Account ID = the account id, Access Key ID + Secret Access Key = the R2 token credentials, CDN / public domain = your custom domain (or r2.dev). Region stays "auto". Save & Test.',
			],
		];
	}

	private static function b2(): array {
		return [
			'label'  => 'Backblaze B2',
			'type'   => 's3',
			'fields' => [ 'bucket', 'region', 'access_key', 'secret_key', 'cdn_domain' ],
			'regions'=> [ 'us-west-004', 'us-west-002', 'us-east-005', 'eu-central-003' ],
			'endpoint_tpl'   => 'https://s3.{region}.backblazeb2.com',
			'public_url_tpl' => 'https://s3.{region}.backblazeb2.com/{bucket}',
			'pricing'=> [
				// https://www.backblaze.com/cloud-storage/pricing
				'storage_gb_month' => 0.006,
				'egress_gb'        => 0.01,
				'free_egress_gb'   => 0,      // free egress up to 3x avg daily storage; modelled via egress_free_multiple
				'egress_free_multiple' => 3,  // 3x stored GB free egress per month
				'class_a_per_10k'  => 0.0,    // uploads (class A) free
				'class_b_per_10k'  => 0.004,  // downloads/class B
				'base_monthly'     => 0,
				'included_gb'      => 10,      // first 10 GB storage free
				'min_storage_gb'   => 0,
				'min_storage_days' => 0,
			],
			'pros'   => [
				'Cheapest pure storage ($6/TB-mo) of the mainstream providers.',
				'Free egress up to 3x your stored data (great via the Bandwidth Alliance / Cloudflare).',
				'Simple pricing, uploads are free, S3-compatible endpoint.',
			],
			'cons'   => [
				'Direct egress beyond the free multiple costs $0.01/GB.',
				'Fewer regions than AWS; latency depends on chosen region.',
				'Pair with a CDN for best delivery performance.',
			],
			'guide'  => [
				'Create a Backblaze account → B2 Cloud Storage → Buckets → Create a Bucket (set "Public" for direct media).',
				'Note the bucket\'s Endpoint (e.g. s3.us-west-004.backblazeb2.com) → the region is the middle segment (us-west-004).',
				'App Keys → Add a New Application Key, scoped to the bucket, with read+write → copy keyID + applicationKey.',
				'Below: set Bucket, Region (e.g. us-west-004), Access Key = keyID, Secret = applicationKey. Save & Test.',
				'Recommended: front it with Cloudflare for free egress, and set that hostname as CDN domain.',
			],
		];
	}

	private static function wasabi(): array {
		return [
			'label'  => 'Wasabi',
			'type'   => 's3',
			'fields' => [ 'bucket', 'region', 'access_key', 'secret_key', 'cdn_domain' ],
			'regions'=> [ 'us-east-1', 'us-east-2', 'us-central-1', 'us-west-1', 'eu-central-1', 'eu-central-2', 'eu-west-1', 'eu-west-2', 'ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2' ],
			'endpoint_tpl'   => 'https://s3.{region}.wasabisys.com',
			'public_url_tpl' => 'https://s3.{region}.wasabisys.com/{bucket}',
			'pricing'=> [
				// https://wasabi.com/pricing/
				'storage_gb_month' => 0.00699, // $6.99/TB-mo
				'egress_gb'        => 0.0,      // no egress fees
				'free_egress_gb'   => 0,
				'class_a_per_10k'  => 0.0,      // no per-request fees
				'class_b_per_10k'  => 0.0,
				'base_monthly'     => 0,
				'included_gb'      => 0,
				'min_storage_gb'   => 1000,     // billed for min 1 TB
				'min_storage_days' => 90,       // 90-day minimum storage duration
				'egress_free'      => true,
			],
			'pros'   => [
				'No egress fees and no API request fees — flat, predictable bills.',
				'Cheap storage ($6.99/TB-mo), S3-compatible.',
				'Great when egress would dominate costs elsewhere.',
			],
			'cons'   => [
				'Minimum billable storage is 1 TB even if you store less.',
				'90-day minimum storage duration — deleting early still bills 90 days.',
				'No native CDN; pair with one for global performance.',
			],
			'guide'  => [
				'Create a Wasabi account → Buckets → Create Bucket; choose a region.',
				'Note the region (e.g. eu-central-1) → endpoint is s3.<region>.wasabisys.com.',
				'Access Keys → Create Access Key → copy Access Key + Secret Key.',
				'Below: set Bucket, Region, paste Access Key + Secret. Save & Test.',
				'Note the 1 TB / 90-day minimums before migrating a small library.',
			],
		];
	}

	private static function spaces(): array {
		return [
			'label'  => 'DigitalOcean Spaces',
			'type'   => 's3',
			'fields' => [ 'bucket', 'region', 'access_key', 'secret_key', 'cdn_domain' ],
			'regions'=> [ 'nyc3', 'sfo3', 'ams3', 'sgp1', 'fra1', 'syd1', 'blr1' ],
			'endpoint_tpl'   => 'https://{region}.digitaloceanspaces.com',
			'public_url_tpl' => 'https://{bucket}.{region}.digitaloceanspaces.com',
			'pricing'=> [
				// https://www.digitalocean.com/pricing/spaces-object-storage
				'storage_gb_month' => 0.02,
				'egress_gb'        => 0.01,
				'free_egress_gb'   => 0,        // modelled via included base below
				'class_a_per_10k'  => 0.0,
				'class_b_per_10k'  => 0.0,
				'base_monthly'     => 5.00,     // $5/mo base
				'included_gb'      => 250,      // includes 250 GB storage
				'included_egress_gb' => 1024,   // includes 1 TB egress
				'min_storage_gb'   => 0,
				'min_storage_days' => 0,
			],
			'pros'   => [
				'Simple flat $5/mo includes 250 GB storage + 1 TB egress.',
				'Built-in CDN (Spaces CDN) with one click.',
				'Easy for sites already on DigitalOcean.',
			],
			'cons'   => [
				'$5/mo minimum even for tiny libraries.',
				'Overage egress $0.01/GB and storage $0.02/GB beyond the included tier.',
				'Fewer regions than AWS.',
			],
			'guide'  => [
				'DigitalOcean → Spaces Object Storage → Create a Spaces bucket; choose a datacenter region (e.g. fra1).',
				'Enable the CDN for the Space if you want edge delivery; note the endpoint <bucket>.<region>.digitaloceanspaces.com.',
				'API → Spaces Keys → Generate New Key → copy Access Key + Secret.',
				'Below: set Bucket (the Space name), Region (e.g. fra1), paste Access Key + Secret. Save & Test.',
			],
		];
	}

	private static function bunny(): array {
		return [
			'label'  => 'Bunny.net Storage',
			'type'   => 'bunny',
			'fields' => [ 'bunny_storage_zone', 'bunny_region', 'secret_key', 'cdn_domain' ],
			'regions'=> [ '', 'la', 'ny', 'sg', 'syd', 'uk', 'se', 'br', 'jh' ], // '' = default (Falkenstein, DE)
			'pricing'=> [
				// https://bunny.net/pricing/  (Edge Storage standard HDD + CDN avg)
				'storage_gb_month' => 0.01,
				'egress_gb'        => 0.01,   // region-tiered $0.005–$0.06; ~$0.01 typical
				'free_egress_gb'   => 0,
				'class_a_per_10k'  => 0.0,
				'class_b_per_10k'  => 0.0,
				'base_monthly'     => 0,      // $1/mo minimum spend applies account-wide
				'included_gb'      => 0,
				'min_storage_gb'   => 0,
				'min_storage_days' => 0,
				'min_account_monthly' => 1.0, // $1/mo minimum charge
			],
			'pros'   => [
				'Storage + global CDN from one vendor; very cheap edge delivery.',
				'Simple API (single access key), instant pull-zone public URLs.',
				'Replication across regions is a toggle.',
			],
			'cons'   => [
				'$1/mo account minimum spend.',
				'Egress price varies by continent (cheap in EU/NA, pricier elsewhere).',
				'Not S3-compatible — its own API (handled natively here).',
			],
			'guide'  => [
				'bunny.net dashboard → Storage → Add Storage Zone; pick a main region (and optional replicas).',
				'Open the zone → FTP & API Access → copy the Password (this is your access key) and note the region code.',
				'Storage → your zone → connect a Pull Zone (CDN). Note its hostname, e.g. <zone>.b-cdn.net.',
				'Below: set Storage Zone name, Region (blank for default DE), Access Key = the zone password, CDN domain = the b-cdn.net (or custom) host. Save & Test.',
			],
		];
	}
}
