import { defu } from "../node_modules/.pnpm/defu@6.1.4/node_modules/defu/dist/defu.mjs";
import { loadEnvFromContext } from "../helpers/load.mjs";
import { ReflectionClass, ReflectionKind } from "@powerlines/deepkit/vendor/type";
import { titleCase } from "@stryke/string-format/title-case";
import { createComponent, createIntrinsic, memo, mergeProps } from "@alloy-js/core/jsx-runtime";
import { For, Show, code, computed, splitProps } from "@alloy-js/core";
import { usePowerlines } from "@powerlines/plugin-alloy/core/contexts/context";
import { ClassDeclaration, ClassMethod, ElseIfClause, FunctionDeclaration, IfStatement, NewExpression, TypeDeclaration, VarDeclaration } from "@alloy-js/typescript";
import { refkey } from "@powerlines/plugin-alloy/helpers/refkey";
import { BuiltinFile } from "@powerlines/plugin-alloy/typescript/components/builtin-file";
import { TSDoc, TSDocExample, TSDocLink, TSDocParam, TSDocRemarks, TSDocReturns, TSDocThrows } from "@powerlines/plugin-alloy/typescript/components/tsdoc";
import { TypeScriptInterface } from "@powerlines/plugin-alloy/typescript/components/typescript-interface";
import { TypescriptObject } from "@powerlines/plugin-alloy/typescript/components/typescript-object";

//#region src/components/env.tsx
/**
* Generates the environment configuration typescript definition for the Powerlines project.
*/
function EnvTypeDefinition(props) {
	const [{ defaultValue, reflection }] = splitProps(props, ["defaultValue", "reflection"]);
	const context = usePowerlines();
	return [
		createComponent(TypeScriptInterface, {
			name: " EnvBase",
			defaultValue,
			reflection,
			"export": true
		}),
		createIntrinsic("hbr", {}),
		createIntrinsic("hbr", {}),
		createComponent(TSDoc, {
			heading: "The environment configuration object with prefixed keys.",
			get children() {
				return createComponent(TSDocRemarks, { children: `The \`Env\` type extends the \`EnvBase\` interface by including additional keys that are prefixed according to the project's configuration. This allows for flexibility in accessing environment variables with different naming conventions.` });
			}
		}),
		createComponent(TypeDeclaration, {
			name: "Env",
			"export": true,
			get children() {
				return code` {
    [Key in keyof EnvBase as Key ${context.config.env.prefix.map((prefix) => `| \`${prefix.replace(/_$/g, "")}_\${Key}\``).join(" ")}]: EnvBase[Key];
}
`;
			}
		}),
		createIntrinsic("hbr", {}),
		createIntrinsic("hbr", {})
	];
}
function ConfigPropertyConditional(props) {
	const [{ context, name }] = splitProps(props, ["context", "name"]);
	return code`propertyName === "${name}" || propertyName.replace(/^(${context.config.env.prefix.sort((a, b) => a.startsWith(b) ? -1 : b.startsWith(a) ? 1 : a.localeCompare(b)).map((prefix) => `${prefix.replace(/_$/, "")}_`).join("|")})/g, "").toLowerCase().replace(/[\\s\\-_]+/g, "") === "${name.toLowerCase().replace(/[\s\-_]+/g, "")}"`;
}
function ConfigPropertyGet(props) {
	const [{ context, property, index }] = splitProps(props, [
		"context",
		"property",
		"index"
	]);
	return [index === 0 ? createComponent(IfStatement, {
		get condition() {
			return [createComponent(ConfigPropertyConditional, {
				get name() {
					return property.getNameAsString();
				},
				context
			}), createComponent(Show, {
				get when() {
					return memo(() => !!property.getAlias())() && property.getAlias().length > 0;
				},
				get children() {
					return [code` || `, createComponent(For, {
						get each() {
							return property.getAlias();
						},
						joiner: code` || `,
						children: (alias) => createComponent(ConfigPropertyConditional, {
							name: alias,
							context
						})
					})];
				}
			})];
		},
		get children() {
			return code`return target["${property.getNameAsString()}"];`;
		}
	}) : createComponent(ElseIfClause, {
		get condition() {
			return [createComponent(ConfigPropertyConditional, {
				get name() {
					return property.getNameAsString();
				},
				context
			}), createComponent(Show, {
				get when() {
					return memo(() => !!property.getAlias())() && property.getAlias().length > 0;
				},
				get children() {
					return [code` || `, createComponent(For, {
						get each() {
							return property.getAlias();
						},
						joiner: code` || `,
						children: (alias) => createComponent(ConfigPropertyConditional, {
							name: alias,
							context
						})
					})];
				}
			})];
		},
		get children() {
			return code`return target["${property.getNameAsString()}"];`;
		}
	})];
}
function ConfigPropertySet(props) {
	const [{ context, property, index }] = splitProps(props, [
		"context",
		"property",
		"index"
	]);
	return [index === 0 ? createComponent(IfStatement, {
		get condition() {
			return [createComponent(ConfigPropertyConditional, {
				get name() {
					return property.getNameAsString();
				},
				context
			}), createComponent(Show, {
				get when() {
					return memo(() => !!property.getAlias())() && property.getAlias().length > 0;
				},
				get children() {
					return [code` || `, createComponent(For, {
						get each() {
							return property.getAlias();
						},
						joiner: code` || `,
						children: (alias) => createComponent(ConfigPropertyConditional, {
							name: alias,
							context
						})
					})];
				}
			})];
		},
		get children() {
			return code`
    target["${property.getNameAsString()}"] = newValue;
    return true;
`;
		}
	}) : createComponent(ElseIfClause, {
		get condition() {
			return [createComponent(ConfigPropertyConditional, {
				get name() {
					return property.getNameAsString();
				},
				context
			}), createComponent(Show, {
				get when() {
					return memo(() => !!property.getAlias())() && property.getAlias().length > 0;
				},
				get children() {
					return [code` || `, createComponent(For, {
						get each() {
							return property.getAlias();
						},
						joiner: code` || `,
						children: (alias) => createComponent(ConfigPropertyConditional, {
							name: alias,
							context
						})
					})];
				}
			})];
		},
		get children() {
			return code`
    target["${property.getNameAsString()}"] = newValue;
    return true;
`;
		}
	})];
}
const createEnvRefkey = refkey("createEnv");
const envRefkey = refkey("env");
const envSerializerRefkey = refkey("EnvSerializer");
/**
* Generates the environment configuration module for the Powerlines project.
*/
function EnvBuiltin(props) {
	const [{ defaultConfig, reflection, children }, rest] = splitProps(props, [
		"defaultConfig",
		"reflection",
		"children"
	]);
	const context = usePowerlines();
	const defaultValue = computed(() => context && loadEnvFromContext(context, process.env));
	const envInstance = computed(() => {
		return new ReflectionClass({
			kind: ReflectionKind.objectLiteral,
			description: `The initial environment configuration state for the ${titleCase(context?.config?.name)} project.`,
			types: []
		}, reflection);
	});
	const reflectionGetProperties = computed(() => reflection?.getProperties().filter((property) => !property.isIgnored()).sort((a, b) => a.getNameAsString().localeCompare(b.getNameAsString())) ?? []);
	const reflectionSetProperties = computed(() => reflection?.getProperties().filter((property) => !property.isIgnored() && !property.isReadonly()).sort((a, b) => a.getNameAsString().localeCompare(b.getNameAsString())) ?? []);
	return createComponent(BuiltinFile, mergeProps({
		id: "env",
		description: "The environment configuration module provides an interface to define environment configuration parameters."
	}, rest, {
		get imports() {
			return defu({ "@powerlines/deepkit/vendor/type": [
				"stringify",
				"serializer",
				"serializeFunction",
				"deserializeFunction",
				"ReflectionKind",
				"Serializer",
				"TemplateState",
				"Type",
				"TypeProperty",
				"TypePropertySignature"
			] }, rest.imports ?? {});
		},
		get children() {
			return [
				createComponent(Show, {
					get when() {
						return Boolean(reflection);
					},
					get children() {
						return [
							createComponent(EnvTypeDefinition, {
								get defaultValue() {
									return defaultValue.value;
								},
								reflection
							}),
							createIntrinsic("hbr", {}),
							createIntrinsic("hbr", {})
						];
					}
				}),
				createComponent(TypescriptObject, {
					name: "initialEnv",
					type: "Partial<EnvBase>",
					defaultValue,
					reflection: envInstance,
					"export": true,
					"const": true,
					doc: "The initial environment configuration object values for the runtime."
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(TSDoc, {
					heading: "The environment configuration serializer for the Powerlines application.",
					get children() {
						return [
							createComponent(TSDocLink, { children: `https://deepkit.io/docs/serialization/serializers` }),
							createComponent(TSDocLink, { children: `https://github.com/marcj/untitled-code/blob/master/packages/type/src/serializer.ts#L1918` }),
							createComponent(TSDocRemarks, { children: `This serializer is used to serialize and deserialize the Powerlines environment configuration.` })
						];
					}
				}),
				createComponent(ClassDeclaration, {
					refkey: envSerializerRefkey,
					name: "EnvSerializer",
					"extends": "Serializer",
					"export": true,
					get children() {
						return createComponent(ClassMethod, {
							name: "constructor",
							"public": true,
							doc: "Initializes a new instance of the `EnvSerializer` class.",
							children: code`
    super("env");

    this.deserializeRegistry.register(
      ReflectionKind.boolean,
      (type: Type, state: TemplateState) => {
        state.addSetter(
          \`typeof \${state.accessor.toString()} !== "boolean" ? \${state.accessor.toString()} === 1 || \${state.accessor.toString()} === "1" || \${state.accessor.toString()}.toLowerCase() === "t" || \${state.accessor.toString()}.toLowerCase() === "true" || \${state.accessor.toString()}.toLowerCase() === "y" || \${state.accessor.toString()}.toLowerCase() === "yes" : \${state.accessor.toString()}\`
        );
      }
    );
`
						});
					}
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(TSDoc, {
					heading: "A {@link EnvSerializer | environment configuration serializer} instance for the Powerlines application.",
					get children() {
						return [
							createComponent(TSDocLink, { children: `https://deepkit.io/docs/serialization/serializers` }),
							createComponent(TSDocLink, { children: `https://github.com/marcj/untitled-code/blob/master/packages/type/src/serializer.ts#L1918` }),
							createComponent(TSDocRemarks, { children: `This serializer is used to serialize and deserialize the Powerlines environment configuration.` })
						];
					}
				}),
				createComponent(VarDeclaration, {
					name: "envSerializer",
					"export": false,
					"const": true,
					get initializer() {
						return createComponent(NewExpression, {
							args: [],
							target: "EnvSerializer"
						});
					}
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(TSDoc, {
					heading: "Serialize a environment configuration object to JSON data objects (not a JSON string).",
					get children() {
						return [
							createComponent(TSDocRemarks, { children: `The resulting JSON object can be stringified using \`JSON.stringify()\`.` }),
							createComponent(TSDocExample, { children: `const json = serializeEnv(env);` }),
							createComponent(TSDocThrows, { children: `ValidationError when serialization or validation fails.` })
						];
					}
				}),
				createComponent(VarDeclaration, {
					name: "serializeEnv",
					"export": true,
					"const": true,
					initializer: "serializeFunction<EnvBase>(envSerializer)"
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(TSDoc, {
					heading: "Deserialize a environment configuration object from JSON data objects to JavaScript objects, without running any validators.",
					get children() {
						return [
							createComponent(TSDocRemarks, { children: `Types that are already correct will be used as-is.` }),
							createComponent(TSDocExample, { children: `const env = deserializeEnv(json);` }),
							createComponent(TSDocThrows, { children: `ValidationError when deserialization fails.` })
						];
					}
				}),
				createComponent(VarDeclaration, {
					name: "deserializeEnv",
					"export": true,
					"const": true,
					initializer: "deserializeFunction<EnvBase>(envSerializer)"
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(TSDoc, {
					heading: "Initializes the Powerlines environment configuration module.",
					get children() {
						return [
							createComponent(TSDocRemarks, { children: `This function initializes the Powerlines environment configuration object.` }),
							createComponent(TSDocParam, {
								name: "environmentConfig",
								children: `The dynamic/runtime configuration - this could include the current environment variables or any other environment-specific settings provided by the runtime.`
							}),
							createComponent(TSDocReturns, { children: `The initialized Powerlines configuration object.` })
						];
					}
				}),
				createComponent(Show, {
					get when() {
						return Boolean(context?.entryPath);
					},
					get children() {
						return createComponent(FunctionDeclaration, {
							refkey: createEnvRefkey,
							async: false,
							"export": true,
							name: "createEnv",
							parameters: [{
								name: "environmentConfig",
								type: `Partial<Env>`,
								optional: false,
								default: "{}"
							}],
							returnType: "Env",
							get children() {
								return [
									code`
  return new Proxy<Env>(
    deserializeEnv({
      ...initialEnv,
      ...environmentConfig
    }) as Env,
    {
      get: (target: EnvBase, propertyName: string) => { `,
									createIntrinsic("hbr", {}),
									createComponent(For, {
										each: reflectionGetProperties,
										children: (property, index) => createComponent(ConfigPropertyGet, {
											index,
											context,
											property
										})
									}),
									code`
            return undefined;
          }, `,
									createIntrinsic("hbr", {}),
									createIntrinsic("hbr", {}),
									code` set: (target: EnvBase, propertyName: string, newValue: any) => { `,
									createIntrinsic("hbr", {}),
									createComponent(For, {
										each: reflectionSetProperties,
										ender: code` else `,
										children: (property, index) => createComponent(ConfigPropertySet, {
											index,
											context,
											property
										})
									}),
									createIntrinsic("hbr", {}),
									code`return false;
      }
    }
  );
`
								];
							}
						});
					}
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(TSDoc, {
					heading: "The environment configuration object.",
					get children() {
						return createComponent(TSDocRemarks, { children: `This object provides access to the environment configuration parameters in the application runtime.` });
					}
				}),
				createComponent(VarDeclaration, {
					refkey: envRefkey,
					name: "env",
					type: "Env",
					"export": true,
					"const": true,
					get initializer() {
						return [code`createEnv(${defaultConfig || "{}"} as Partial<Env>);`];
					}
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(VarDeclaration, {
					"export": true,
					"const": true,
					name: "isCI",
					doc: "Detect if the application is running in a continuous integration (CI) environment.",
					initializer: code`Boolean(
          env.CI ||
          env.RUN_ID ||
          env.AGOLA_GIT_REF ||
          env.AC_APPCIRCLE ||
          env.APPVEYOR ||
          env.CODEBUILD ||
          env.TF_BUILD ||
          env.bamboo_planKey ||
          env.BITBUCKET_COMMIT ||
          env.BITRISE_IO ||
          env.BUDDY_WORKSPACE_ID ||
          env.BUILDKITE ||
          env.CIRCLECI ||
          env.CIRRUS_CI ||
          env.CF_BUILD_ID ||
          env.CM_BUILD_ID ||
          env.CI_NAME ||
          env.DRONE ||
          env.DSARI ||
          env.EARTHLY_CI ||
          env.EAS_BUILD ||
          env.GERRIT_PROJECT ||
          env.GITEA_ACTIONS ||
          env.GITHUB_ACTIONS ||
          env.GITLAB_CI ||
          env.GOCD ||
          env.BUILDER_OUTPUT ||
          env.HARNESS_BUILD_ID ||
          env.JENKINS_URL ||
          env.LAYERCI ||
          env.MAGNUM ||
          env.NETLIFY ||
          env.NEVERCODE ||
          env.PROW_JOB_ID ||
          env.RELEASE_BUILD_ID ||
          env.RENDER ||
          env.SAILCI ||
          env.HUDSON ||
          env.SCREWDRIVER ||
          env.SEMAPHORE ||
          env.SOURCEHUT ||
          env.STRIDER ||
          env.TASK_ID ||
          env.RUN_ID ||
          env.TEAMCITY_VERSION ||
          env.TRAVIS ||
          env.VELA ||
          env.NOW_BUILDER ||
          env.APPCENTER_BUILD_ID ||
          env.CI_XCODE_PROJECT ||
          env.XCS || false
        );
        `
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(TSDoc, {
					heading: "Detect the \\`mode\\` of the current runtime environment.",
					get children() {
						return createComponent(TSDocRemarks, { children: code`The \`mode\` is determined by the \`MODE\` environment variable, or falls back to the \`NEXT_PUBLIC_VERCEL_ENV\`, \`NODE_ENV\`, or defaults to \`production\`. While the value can potentially be any string, it is generally recommended to only allow a value in the following list:
          - \`production\`
          - \`test\`
          - \`development\`
          ` });
					}
				}),
				createComponent(VarDeclaration, {
					"export": true,
					"const": true,
					name: "mode",
					initializer: code`String(env.MODE) || "production"; `
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(VarDeclaration, {
					"export": true,
					"const": true,
					name: "isProduction",
					doc: "Detect if the application is running in `\"production\"` mode",
					initializer: code`["prd", "prod", "production"].includes(mode.toLowerCase()); `
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(VarDeclaration, {
					"export": true,
					"const": true,
					name: "isTest",
					doc: "Detect if the application is running in `\"test\"` mode",
					initializer: code`["tst", "test", "testing", "stg", "stage", "staging"].includes(mode.toLowerCase()) || env.TEST; `
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(VarDeclaration, {
					"export": true,
					"const": true,
					name: "isDevelopment",
					doc: "Detect if the application is running in `\"development\"` mode",
					initializer: code`["dev", "development"].includes(mode.toLowerCase()); `
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(VarDeclaration, {
					"export": true,
					"const": true,
					name: "isDebug",
					doc: "Detect if the application is currently being debugged",
					initializer: code`Boolean(isDevelopment && env.DEBUG); `
				}),
				createIntrinsic("hbr", {}),
				createIntrinsic("hbr", {}),
				createComponent(Show, {
					get when() {
						return Boolean(children);
					},
					children
				})
			];
		}
	}));
}

//#endregion
export { EnvBuiltin, EnvTypeDefinition };
//# sourceMappingURL=env.mjs.map