from uuid import UUID

from flows_sdk.blocks import Routing
from flows_sdk.flows import Flow
from flows_sdk.implementations.idp_v42 import additional_blocks, idp_blocks
from flows_sdk.implementations.idp_v42.flows_version import FLOWS_VERSION, FLOWS_VERSION_DOTTED
from flows_sdk.implementations.idp_v42.idp_values import IDPCoreManifest
from flows_sdk.package_utils import export_flow
from flows_sdk.utils import str_to_deterministic_uuid_4

# If you are creating a custom version of this flow, choose a different UUID and identifier
# here and pass the correct identifier into IDPCoreBlock(identifier=...) within your flow.
IDP_CORE_IDENTIFIER = f'IDP_CORE_{FLOWS_VERSION}_EXAMPLE'
IDP_CORE_UUID = str(str_to_deterministic_uuid_4(IDP_CORE_IDENTIFIER))
IDP_CORE_TITLE = f'Document Processing Subflow {FLOWS_VERSION_DOTTED} - flows-sdk example'
NO_LABEL = 'No'
YES_LABEL = 'Yes'


def idp_workflow() -> Flow:
    file_filter = additional_blocks.FileFilterBlock(reference_name='file_filter')

    bootstrap_submission = idp_blocks.SubmissionBootstrapBlock(
        trigger=file_filter.output('result.filtered_trigger'),
        reference_name='submission_bootstrap',
    )

    case_collation_task = idp_blocks.MachineCollationBlock(
        reference_name='machine_collation',
        submission=bootstrap_submission.output('submission'),
        cases=bootstrap_submission.output('api_params.cases'),
    )

    machine_classification = idp_blocks.MachineClassificationBlock(
        reference_name='machine_classification',
        submission=case_collation_task.output('submission'),
        api_params=bootstrap_submission.output('api_params'),
    )

    manual_classification = idp_blocks.ManualClassificationBlock(
        reference_name='manual_classification',
        submission=machine_classification.output('submission'),
        api_params=bootstrap_submission.output('api_params'),
    )

    manual_classification_routing = Routing(
        reference_name='manual_classification_routing',
        decision=machine_classification.output('needs_manual_classification'),
        title='Is Manual Classification needed?',
        branches=[
            Routing.Branch(
                case='false', label=NO_LABEL, blocks=[], output='machine_classification'
            ),
        ],
        default_branch=Routing.DefaultBranch(label=YES_LABEL, blocks=[manual_classification]),
    )

    machine_identification = idp_blocks.MachineIdentificationBlock(
        reference_name='machine_identification',
        submission=manual_classification_routing.output('submission'),
        api_params=bootstrap_submission.output('api_params'),
    )

    manual_identification = idp_blocks.ManualIdentificationBlock(
        reference_name='manual_identification',
        submission=machine_identification.output('submission'),
        api_params=bootstrap_submission.output('api_params'),
    )

    manual_identification_routing = Routing(
        reference_name='manual_identification_routing',
        decision=machine_identification.output('needs_manual_identification'),
        title='Is Manual Identification needed?',
        branches=[
            Routing.Branch('false', blocks=[], label=NO_LABEL, output='machine_identification'),
        ],
        default_branch=Routing.DefaultBranch(blocks=[manual_identification], label=YES_LABEL),
    )

    machine_transcription = idp_blocks.MachineTranscriptionBlock(
        reference_name='machine_transcription',
        submission=manual_identification_routing.output('submission'),
        api_params=bootstrap_submission.output('api_params'),
    )

    manual_transcription = idp_blocks.ManualTranscriptionBlock(
        reference_name='manual_transcription',
        submission=machine_transcription.output('submission'),
        api_params=bootstrap_submission.output('api_params'),
    )

    manual_transcription_routing = Routing(
        reference_name='manual_transcription_routing',
        decision=machine_transcription.output('needs_manual_transcription'),
        title='Is Manual Transcription needed?',
        branches=[
            Routing.Branch('false', blocks=[], label=NO_LABEL, output='machine_transcription'),
        ],
        default_branch=Routing.DefaultBranch(blocks=[manual_transcription], label=YES_LABEL),
    )

    flexible_extraction = idp_blocks.FlexibleExtractionBlock(
        reference_name='flexible_extraction',
        submission=manual_transcription_routing.output('submission'),
        api_params=bootstrap_submission.output('api_params'),
    )

    flexible_extraction_routing = Routing(
        reference_name='flexible_extraction_routing',
        decision=machine_transcription.output('needs_flexible_extraction'),
        title='Is Flexible Extraction needed?',
        branches=[
            Routing.Branch(
                'false', blocks=[], label=NO_LABEL, output='manual_transcription_routing'
            ),
        ],
        default_branch=Routing.DefaultBranch(blocks=[flexible_extraction], label=YES_LABEL),
    )

    reprocessing = idp_blocks.ReprocessingBlock(
        reference_name='reprocessing',
        submission=flexible_extraction_routing.output('submission'),
    )

    document_rendering = idp_blocks.DocumentRendererBlock(
        reference_name='document_rendering',
        submission=reprocessing.output('submission'),
        is_reprocessing=reprocessing.output('is_reprocessing'),
    )

    submission_complete = idp_blocks.SubmissionCompleteBlock(
        reference_name='complete_submission',
        submission=document_rendering.output('submission'),
        is_reprocessing=reprocessing.output('is_reprocessing'),
    )

    return Flow(
        uuid=UUID(IDP_CORE_UUID),
        owner_email='flows-sdk@hyperscience.ai',
        title=IDP_CORE_TITLE,
        description='A read-only subflow containing steps to process documents into '
        'machine-readable output.',
        manifest=IDPCoreManifest(
            flow_identifier=IDP_CORE_IDENTIFIER, roles=['read_only', 'supporting', 'idp_core']
        ),
        output={'submission': submission_complete.output('submission')},
        blocks=[
            file_filter,
            bootstrap_submission,
            case_collation_task,
            machine_classification,
            manual_classification_routing,
            machine_identification,
            manual_identification_routing,
            machine_transcription,
            manual_transcription_routing,
            flexible_extraction_routing,
            reprocessing,
            document_rendering,
            submission_complete,
        ],
    )


def entry_point_workflow() -> Flow:
    return idp_workflow()


if __name__ == '__main__':
    export_flow(entry_point_workflow())
